什么是熔断降级
在微服务架构一定要去预防微服务雪崩问题,微服务雪崩问题是指在微服务架构中,当一个服务出现故障时,由于服务之间的依赖关系,故障可能会传播到其他服务,导致大规模的服务失败,系统无法正常运行。这种情况就像雪崩一样,最初一个小问题最终引发了整个系统的崩溃。
简单理解微服务雪崩就是微服务之间相互调用,因为调用链中的一个服务故障,引起整个链路都无法访问的情况。
常用的预防微服务雪崩的的方法:
-
超时处理:设定超时时间,请求超过一定时间没有响应就返回错误信息,不会无休止等待。
-
熔断降级:当服务的异常数或异常比例超过了预设的阈值时,熔断器会进入开启状态,暂时中断对该服务的请求,此时走降级方法,能够快速响应,确保系统的基本功能能够继续运行。
-
限流:限制对服务的请求速率,避免短时间内大量的请求导致系统崩溃。
-
线程池 隔离:给要请求的资源分配一个线程池,线程池去控制请求数量
5. 信号量 隔离:使用计数器模式,记录请求资源的并发线程数量,达到信号量上限时,禁止新的请求。
信号量隔离适合同步请求,控制并发数,比如:对文件的下载并发数进行控制。
大多数场景都适合使用线程池隔离,对于需要同步操作控制并发数的场景可以使用信号量隔离。
使用sentinel实现熔断降级
目的: 熔断降级是微服务保护的一种方法,当使用Feign进行远程调用,在客户端通过熔断降级措施进行微服务保护。
定位: Sentinel定位是分布式系统的流量防卫兵。目前互联网应用基本上都使用微服务,微服务的稳定性是一个很重要的问题,而限流、熔断降级是微服务保持稳定的一个重要的手段。
在Sentinel之前其实就有Hystrix做熔断降级的事情,我们都知道出现新的事物肯定是原来的东西有不足的地方。参考文章
如下图:
订单服务请求查询地址簿服务,在进行feign远程调用过程出现异常将走降级方法,当异常比例或异常数达到一定的阈值将触发熔断,熔断期间将直接走降级逻辑快速响应。
当地址簿服务恢复后,熔断时间结束此时会再次尝试请求地址簿服务,如果成功请求将关闭熔断,恢复原来的链路。
根据上图可知,熔断、降级发生在客户端,下边在订单管理服务(调用customer的客户端)定义CustomerClient类用于请求customer服务。
这里是以服务提供者为单独定义远程调用Client类,如果要远程调用服务则定义CustomerClient 类。
@Component
@Slf4j
public class CustomerClient {
@Resource
private AddressBookApi addressBookApi;
@SentinelResource(value = "getAddressBookDetail", fallback = "detailFallback", blockHandler = "detailBlockHandler")
public AddressBookResDTO getDetail(Long id) {
log.error("根据id查询地址簿,id:{}", id);
// 调用其他微服务方法
AddressBookResDTO detail = addressBookApi.detail(id);
return detail;
}
//执行异常走
public AddressBookResDTO detailFallback(Long id, Throwable throwable) {
log.error("非限流、熔断等导致的异常执行的降级方法,id:{},throwable:", id, throwable);
return null;
}
//熔断后的降级逻辑
public AddressBookResDTO detailBlockHandler(Long id, BlockException blockException) {
log.error("触发限流、熔断时执行的降级方法,id:{},blockException:", id, blockException);
return null;
}
}
@SentinelResource注解的属性说明:
value: 用于定义资源的名称,即 Sentinel 会对该资源进行流量控制和熔断降级。
fallback :非限流、熔断等导致的异常执行的降级方法
blockHandler :触发限流、熔断时执行的降级方法
使用@EnableFeignClients扫描Feign接口,生成代理对象。
@Slf4j
@Configuration
@EnableFeignClients(basePackages = "com.jzo2o.api")
@Import({com.jzo2o.utils.MyQueryMapEncoder.class})
@ConditionalOnProperty(prefix = "feign", name = "enable", havingValue = "true")
public class ClientScanConfiguration {
}
测试
1、通过接口文档测试下单接口,触发customerClient.getDetail(addressBookId);
2、在sentinel中配置熔断规则
为了方便测试熔断效果配置异常数规则,如下:
5秒以内最少请求2次,有1次异常则进行熔断。熔断时长为30秒。