Hystrix 服务熔断
容错机制: 微服务和分布式里面,容错是必须要考虑的!通常的做法有两种
一种是重试机制,对于预期的短暂故障问题,可以重试解决;
二是使用断路器模式,即将受保护的服务封装到一个可以监控故障的断路器里面,当故障达到一定的值,断路器将会跳闸,断路器对象返回错误!
断路器状态机: 1.closed,熔断器关闭状态,调用失败次数累计到一定阈值/比例,启动熔断机制,进入打开状态 2.open,熔断器打开状态,对服务直接返回错误,直接服务降级 3.half open,熔断器打开状态达到了一定的时间,会进入半熔断状态,允许定量的服务请求主逻辑。如果都调用成功,或者一定比例成功,则认为恢复,关闭熔断器;否则,熔断器回到打开状态
断路器模式设计状态机(三种状态)
Closed(熔断器的关闭状态):熔断器关闭状态,调用失败次数累计到一定阈值/比例,启动熔断机制,进入打开状态
Open(熔断器打开状态):熔断器打开状态,对服务直接返回错误,直接服务降级
Half Open(熔断器半熔断状态):熔断器打开状态达到了一定的时间,会进入半熔断状态,允许定量的服务请求主逻辑。如果都调用成功,或者一定比例成功,则认为恢复,关闭熔断器;否则,熔断器回到打开状态
原理:调用失败次数累计达到一定的阈值或比例,就会启动熔断机制,熔断器处于打开状态,此时对服务都直接返回错误;但设计了一个时钟选项,默认设置了一个时间段——休眠时间窗[可修改],过了这段时间,会进入半熔断状态,即允许定量的服务请求(尝试熔断请求命令)。如果调用都成功,或成功次数达到一定比例,则会认为恢复了,会关闭熔断器!否则认为还没好,又回到熔断器打开状态。
- sleepWindowInMilliseconds:休眠时间窗口
- requestVolumeThreshold:最小的请求数
- errorThresholdPercentage:服务错误百分比(比如百分之70,就是10个请求,有7个错误)
Product 微服务项目
@PostMapping("/listForOrder") public List<ProductInfoOutput> listForOrder(@RequestBody List<String> productIdList) { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } return productService.findList(productIdList); }
Order 微服务项目
package com.imooc.order.controller; import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import java.util.Arrays; @RestController @DefaultProperties(defaultFallback = "defaultFallback") public class HystrixController { @HystrixCommand(commandProperties = { @HystrixProperty(name = "circuitBreaker.enabled", value = "true"), //设置熔断 @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), // 请求数达到后才计算 @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), // 熔断时间 @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"), // 错误率 }) @GetMapping("/getProductInfoList") public String getProductInfoList(@RequestParam("number") Integer number) { if (number % 2 == 0) { return "success"; } RestTemplate restTemplate = new RestTemplate(); return restTemplate.postForObject("http://127.0.0.1:8005/product/listForOrder", Arrays.asList("157875196366160022"), String.class); } private String defaultFallback() { return "默认提示:太拥挤了, 请稍后再试~~"; } }
- 此时默认 1s(为了达到降级效果),这里模拟了一个奇数偶数判断是为了模拟熔断的场景。