多个微服务之间调用的时候,假如微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务,这就是所谓的"扇出"。
如果扇出的链路上某个微服务的调用响应的时间过长或者不可用,对微服A的调用就会占用越来越多的系统资源,进而引起系统崩溃,即"雪崩效应"。
这时就需要一个组件(hytrix),来保证微服务出现故障时,不会导致整个系统出现雪崩效应,以提高分布式系统弹性。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
//超过3秒钟降级到userInfoListFallBack
@HystrixCommand(fallbackMethod = "userInfoListFallBack",commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds"
,value = "3000")})
@EnableHystrix
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
@HystrixCommand(fallbackMethod = "fallbackMethod")
@EnableHystrix
@RestController
@RequestMapping("/user")
@DefaultProperties(defaultFallback = "globalFallback")
@Slf4j
public class UserConsumer {
@GetMapping("/userInfoList")
@HystrixCommand
public List<UserInfo> userInfoList(){
}
}
不管是业务方法指定的降级方法还是全局降级方法,它们都必须和业务方法在同一个类中才能生效,业务逻辑与降级逻辑耦合度极高。
feign:
# hystrix:
# enabled: true
circuitbreaker:
enabled: true
@FeignClient(value = "USER-SERVICE",fallback = UserServiceFallBack.class)
public class UserServiceFallBack implements UserService{
熔断机制是为了应对雪崩效应而出现的一种微服务链路保护机制。
在熔断机制中涉及了三种熔断状态:
在统计时间窗内,请求总数必须到达一定的数量级,Hystrix 才可能会将熔断器打开进入熔断开启转态,而这个请求数量级就是 请求总数阀值。Hystrix 请求总数阈值默认为 20,这就意味着在统计时间窗内,如果服务调用次数不足 20 次,即使所有的请求都调用出错,熔断器也不会打开。 |
| circuitBreaker.errorThresholdPercentage | 错误百分比阈值。
当请求总数在统计时间窗内超过了请求总数阀值,且请求调用出错率超过一定的比例,熔断器才会打开进入熔断开启转态,而这个比例就是错误百分比阈值。错误百分比阈值设置为 50,就表示错误百分比为 50%,如果服务发生了 30 次调用,其中有 15 次发生了错误,即超过了 50% 的错误百分比,这时候将熔断器就会打开。 |
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled",value = "true"),// 是否开启断路器
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value = "10000")//时间窗口10秒
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),// 请求次数
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "30000"), // 时间窗口期
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),// 失败率达到多少后跳闸
})
public interface UserService {
public String paymentCircuitBreaker(@PathVariable("id") Integer id);
}
@Service
public class UserServiceImpl implements UserService {
@Override
@HystrixCommand(fallbackMethod = "paymentCircuitBreakerFallback",commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled",value = "true"),// 是否开启断路器
@HystrixProperty(name = HystrixPropertiesManager.METRICS_ROLLING_STATS_TIME_IN_MILLISECONDS,value = "10000"),
@HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD,value = "10"),// 请求次数
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "30000"), // 时间窗口期
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),// 失败率达到多少后跳闸
})
public String paymentCircuitBreaker(Integer id) {
if(id < 0) {
throw new RuntimeException("******id 不能负数");
}
String serialNumber = UUID.randomUUID().toString();
return Thread.currentThread().getName()+"\t"+"调用成功,流水号: " + serialNumber;
}
public String paymentCircuitBreakerFallback(@PathVariable("id") Integer id) {
return "id 不能负数,请稍后再试,/(ㄒoㄒ)/~~ id: " +id;
}
}