SpringCloud(八)微服务的空气开关-Hystrix
熔断器 (hystrix)
断路器很好理解, 当Hystrix Command请求后端服务失败数量超过一定比例(默认50%), 断路器会切换到开路状态(Open). 这时所有请求会直接失败而不会发送到后端服务. 断路器保持在开路状态一段时间后(默认5秒), 自动切换到半开路状态(HALF-OPEN). 这时会判断下一次请求的返回情况, 如果请求成功, 断路器切回闭路状态(CLOSED), 否则重新切换到开路状态(OPEN). Hystrix的断路器就像我们家庭电路中的保险丝, 一旦后端服务不可用, 断路器会直接切断请求链, 避免发送大量无效请求影响系统吞吐量, 并且断路器有自我检测并恢复的能力.
熔断器开关相互转换的逻辑如下图:
Fallback
Fallback相当于是降级操作. 对于查询操作, 我们可以实现一个fallback方法, 当请求后端服务出现异常的时候, 可以使用fallback方法返回的值. fallback方法的返回值一般是设置的默认值或者来自缓存.
资源隔离
在Hystrix中, 主要通过线程池来实现资源隔离. 通常在使用的时候我们会根据调用的远程服务划分出多个线程池. 例如调用产品服务的Command放入A线程池, 调用账户服务的Command放入B线程池. 这样做的主要优点是运行环境被隔离开了. 这样就算调用服务的代码存在bug或者由于其他原因导致自己所在线程池被耗尽时, 不会对系统的其他服务造成影响. 但是带来的代价就是维护多个线程池会对系统带来额外的性能开销. 如果是对性能有严格要求而且确信自己调用服务的客户端代码不会出问题的话, 可以使用Hystrix的信号模式(Semaphores)来隔离资源.
HystrixCommand
HystrixCommand 表明该方法为hystrix包裹,可以对依赖服务进行隔离、降级、快速失败、快速重试等等hystrix相关功能
该注解属性较多,下面讲解其中几个
fallbackMethod 降级方法
commandProperties 普通配置属性,可以配置HystrixCommand对应属性,例如采用线程池还是信号量隔离、熔断器熔断规则等等
ignoreExceptions 忽略的异常,默认HystrixBadRequestException不计入失败
groupKey() 组名称,默认使用类名称
commandKey 命令名称,默认使用方法名
Dashboard
开启dashboard需要引入
1 2 3 4 5 6 7 8 9 |
<!-- 监控页面 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> |
运行工程,可以访问 http://localhost:9090/hystrix.stream 获取dashboard信息,默认最大打开5个终端获取监控信息,可以增加delay参数指定获取监控数据间隔时间
直接访问hystrix.stream肯定是不明智的,官方提供监控.war包,下载后放入tomcat中,得到如下界面
输入http://localhost:9090/hystrix.stream,以及监控间隔以及名称,之后会看到如下页面
页面详解
Simple
Ribbon实现
在http://start.spring.io/中,输入eureka discovery、ribbon、hystrix、hystrix dashboard快速生成ribbon-hystrix服务调用项目。
与正常的ribbon实现一致,只是需要在请求的方法前添加
@HystrixCommand(fallbackMethod = “fireError”)注解,声明当熔断触发时,回调的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
package com.hanson.hystrix; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.cloud.client.SpringCloudApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; //注解整合了多个注解,@SpringBootApplication、@EnableDiscoveryClient、@EnableCircuitBreaker等 @SpringCloudApplication @RestController public class HystrixApplication { public static void main(String[] args) { SpringApplication.run(HystrixApplication.class, args); } @Autowired RestTemplate client; private long preTime = System.currentTimeMillis(); @Value("${server.port}") private String port; @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } //熔断触发的callback方法,方法名为fireError @HystrixCommand(fallbackMethod = "fireError") @RequestMapping("/") public String helloWorld() { //hanson-service 为服务提供者的配置的spring.application.name String forObject = client.getForObject("http://hanson-service/", String.class); long nowTime = System.currentTimeMillis(); try { if((nowTime - preTime) > 5 * 1000){ //俩次请求间隔大于五秒,模拟一个异常,触发熔断 throw new RuntimeException("call hanson service fail."); } } finally { preTime = nowTime; } forObject = String.format("port:%s %s",port,forObject); System.out.println(); return forObject; } //如果保护的方法有参数,此处可以传递与其一致的参数 public String fireError() { return "some exception occur call fallback method."; } } |
Feign实现
在http://start.spring.io/中,输入eureka discovery、feign、hystrix、hystrix dashboard快速生成feign-hystrix服务调用项目。
Feign是自带断路器的,在D版本的Spring Cloud中,它没有默认打开。需要在配置文件中配置打开它,在配置文件加以下代码:
feign.hystrix.enabled=true
改造之前的代码,在HansonService 接口的feignClient注解上添加fallback指定一个此接口的熔断处理类。
@FeignClient(value = “hanson-service”,fallback = HansonServiceHystrix.class )
HansonServiceHystrix,实现HansonService接口,添加熔断发生后处理逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
package com.hanson.hystrix; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; /** * 模拟客户请求,接口写在了本类中。应该单独封装为一个单独接口 * @author THINK * */ @RestController public class ConsumerController { @Autowired HansonService service;//注入定义的接口 @RequestMapping("/") public String helloWorld(){ /** * 使用@FeignClient("hanson-service") 指定要访问的service为hanson-service,由于get()对应的mapping为@RequestMapping(value = "/", method = GET) 那么该方法实际调用url为 * http://hanson-service/,因此在执行此接口时,实际是访问了http://hanson-service/ */ String string = service.get(); System.out.println(string); return string; } /** * feigen接口 */ @FeignClient(value = "hanson-service",fallback = HansonServiceHystrix.class )//声明此接口访问hanson-service-->与服务提供者的配置的spring.application.name一致 interface HansonService{ @RequestMapping(value = "/",method = RequestMethod.GET) String get(); } /** * 注册至spring */ @Component class HansonServiceHystrix implements HansonService{ @Override public String get() { return "some exception occur call fallback method."; } } } |
可以看到当访问间隔超过五秒,或者当后端的服务提供者挂掉时,服务会返回some exception occur call fallback method.说明熔断触发了fireError方法,快速返回失败,释放资源,不会对后续的服务造成压力。
发表评论