Hystrix 产生背景
在微服务架构中,我们将系统拆分成了很多服务单元,各单元的应用间通过服务注册 与订阅的方式互相依赖。由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服务自身问题出现调用故障或延迟,而这些问 题会直接导致调用方的对外服务也出现延迟,若此时调用方的请求不断增加,最后就会因 等待出现故障的依赖方响应形成任务积压,最终导致自身服务的瘫痪。
为了解决这样的问题,产生了断路器等一系列的服务保护机。
断路器模式源于 Martin Fowler 的 Circuit Breaker 一文。“断路器”本身是一种开关装置,用于在电路上保护线路过载,当线路中有电器发生短路时,“断路器”能够及时切断故障电路,防止发生过载、发热甚至起火等严重后果。
在分布式架构中,断路器模式的作用也是类似的,当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个错误响应,而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间用不释放,避免了故障在分布式系统中的蔓延。
针对上述问题,SpringCloudHystrix实现了断路器、线程隔离等一系列服务保护功能。 它也是基于Netflix的开源框架Hystrix实现的,该框架的目标在于通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Hystrix具备服 务降级、服务熔断、线程和信号隔离、请求缓存、请求合并以及服务监控等强大功能。接下来,我们就从一个简单示例开始对Spring Cloud Hystrix的学习与使用。
1、添加依赖包
<!-- 加入断路器依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.0.2.RELEASE</version> </dependency>
基础配置如下:
# 设置熔断超时时间 hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=10000 # 关闭Hystrix功能(不要和上面的配置一起使用) feign.hystrix.enabled=false # 关闭熔断功能 hystrix.command.default.execution.timeout.enabled=false
如果针对某一个接口配置,比如/hello接口,可以按照如下写法:
# 设置熔断超时时间 hystrix.command.hello.execution.isolation.thread.timeoutInMilliseconds=10000 # 关闭熔断功能 hystrix.command.hello.execution.timeout.enabled=false
@HystrixCommand(fallbackMethod = "helloFallBack") // 注解指定发生错误时的回调方法 public String helloService() { return restTemplate.getForObject("http://producer/hello", String.class); } public String helloFallBack() { return "Error occurred !"; }
在Feign中如何配置Hystrix的服务降级呢?很简单,新建一个类,实现HelloService接口,如下:
@Component public class HelloServiceFallback implements HelloService { @Override public String hello() { return "hello error"; } @Override public String hello(String name) { return "error " + name; } @Override public Book hello(String name, String author, Integer price) { Book book = new Book(); book.setName("error"); return book; } @Override public String hello(Book book) { return "error book"; } }
这里方法实现的逻辑都是相应的服务降级逻辑。然后在@FeignClient注解中指定服务降级处理类即可,如下:
@FeignClient(value = "hello-service",fallback = HelloServiceFallback.class) public interface HelloService { @RequestMapping("/hello") String hello(); @RequestMapping(value = "/hello1", method = RequestMethod.GET) String hello(@RequestParam("name") String name); @RequestMapping(value = "/hello2", method = RequestMethod.GET) Book hello(@RequestHeader("name") String name, @RequestHeader("author") String author, @RequestHeader("price") Integer price); @RequestMapping(value = "/hello3", method = RequestMethod.POST) String hello(@RequestBody Book book); }
如果不想某个Feign Client使用Hystrix的话,可以使用如下配置:
@FeignClient(name = "eureka-client-demo", configuration = DisableHystrix.class) public interface DemoFeignClient { @GetMapping("/hello") public String hello(); } @Configuration public class DisableHystrix { @Bean @Scope("prototype") public Feign.Builder feignBuilder() { return Feign.builder(); } }
此时我们只启动eureka-server和feign-consumer,然后访问相应的接口,可以看到如下结果(注意这里需要在application.properties中配置feign.hystrix.enabled=true,新版本(Dalston.SR3)的Spring Cloud Feign默认是关闭了Hystrix功能的):
Spring Cloud Feign支持对请求和响应进行GZIP压缩,以提高通信效率,配置方式如下:
# 配置请求GZIP压缩 feign.compression.request.enabled=true # 配置响应GZIP压缩 feign.compression.response.enabled=true # 配置压缩支持的MIME TYPE feign.compression.request.mime-types=text/xml,application/xml,application/json # 配置压缩数据大小的下限 feign.compression.request.min-request-size=2048
Feign为每一个FeignClient都提供了一个feign.Logger实例,我们可以在配置中开启日志,开启方式很简单,分两步:
第一步:application.properties中配置日志输出
application.properties中配置如下内容,表示设置日志输出级别:
# 开启日志 格式为logging.level.+Feign客户端路径 logging.level.org.sang.HelloService=debug
第二步:入口类中配置日志Bean
入口类中配置日志Bean,如下:
@Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; }
如此之后,控制台就会输出请求的详细日志。