学习
Spring Cloud
之路,文中Spring Boot
版本为2.1.3.RELEASE
,Spring Cloud
版本为Greenwich.SR1
。因能力有限,难免会有不足或者错误之处,还望不吝指正,谢!
Hystrix,即熔断器,GitHub主页:https://github.com/Netflix/Hystrix/。
Hystrix是Netflix开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败。
熔断器Hystrix是容错管理工具,作用是通过隔离、控制服务从而对延迟和故障提供更强大的容错能力,避免整个系统被拖垮。
复杂分布式架构通常都具有很多依赖,当一个应用高度耦合其它服务时非常危险且容易导致失败,这种失败很容易伤害服务的调用者,最后导致一个接一个的连接错误,应用本身就处在被拖垮的风险中,最后失去控制,就像在一个高流量的网站中,某个单一的后端一旦发生延迟,将会在数秒内导致所有应用资源被耗尽。如何处理这些问题是有关系统性能和效率的关键性问题。
当在系统高峰时期,大量对微服务的调用可能会堵塞远程服务器的线程池,如果这个线程池没有和主应用服务器的线程池隔离,就可能导致整个服务器挂机。
Hystrix使用自己的线程池,这样和主应用服务器线程池隔离,如果调用话费很长时间,会停止调用,不同的命令或命令组能够被配置使用它们各自的线程池,可以隔离不同的服务。
熔断机制的原理很简单,像家里的电路熔断器,如果电路发生短路能立刻熔断电路,避免发生灾难。在分布式系统中应用这一模式之后,服务调用方可以自己进行判断某些服务反应慢或者存在大量超时的情况时,能够主动熔断,防止整个系统被拖垮。
不同于电路熔断只能断不能自动重连,Hystrix可以实现弹性容错,当情况好转之后,可以自动重连。这就好比魔术师把鸽子变没了容易,但是真正考验技术的是如何把消失的鸽子再变回来。
通过断路的方式,可以将后续请求直接拒绝掉,一段时间之后允许部分请求通过,如果调用成功则回到电路闭合状态,否则继续断开。
以之前的user-consumer为例,修改代码如下:
主要的maven依赖:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-hystrixartifactId>
dependency>
添加注解@EnableHystrix
或者@EnableCircuitBreaker
(官网例子中是用的这个)
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class UserConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(UserConsumerApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
private RestTemplate restTemplate;
@Override
@HystrixCommand(fallbackMethod = "helloFallbackMethod")
public Map<String,Object> hello(String name) {
StopWatch watch = new StopWatch();
watch.start();
StringBuffer buffer = new StringBuffer("http://").append("user-provider").append("/user/").append(name);
Map<String,Object> map = restTemplate.getForObject(buffer.toString(), Map.class);
watch.stop();
System.err.println("时间=" + watch.getTotalTimeSeconds());
return map;
}
public Map<String,Object> helloFallbackMethod(String name){
Map<String,Object> map = new HashMap<>(2);
map.put("msg", "操作异常");
return map;
}
}
@HystrixCommand(fallbackMethod = "helloFallbackMethod")
声明一个失败回滚处理函数,当hello执行超时(默认是1000毫秒),就会执行fallback函数,返回错误提示。编写一个Junit测试方法,进行测试:
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserConsumerApplicationTests {
@Autowired
private UserService userService;
@Test
public void testHtx(){
Map map = userService.hello("Cindy");
System.err.println(map);
}
}
如果在提供者服务可连通的情况下,依然执行的
fallbackMethod
这里,可以将Hystrix 超时时间设置的长一些(默认是一秒)。
修改user-consumer配置文件.yml,增加以下代码:
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 5000 # 设置hystrix的超时时间为5000ms
具体Hystrix的属性properties设置请参阅 Hystrix wiki
我们启动Eureka,具体请参阅 Spring Cloud 学习 | - 01 - Eureka服务注册与发现 一文。
服务提供者不可用时(停掉服务),输出结果:
服务提供者可用时,结果: