微服务保护和分布式事务(3)
1.3 请求限流:
这样就把查询购物车列表这个簇点资源的流量限制在了每秒 6 个,也就是最大 QPS 为 6。
1.4 线程隔离:
限流可以降低服务器压力,尽量减少因并发流量引起的服务故障的概率,但并不能完全避免服务故障。一旦某个服务出现故障,我们必须隔离对这个服务的调用,避免发生雪崩。
1.4.1 OpenFeign 整合 Sentinel:
application.yml文件,开启 Feign 的 sentinel 功能:
feign: sentinel: enabled: true # 开启feign对sentinel的支持
1.4.2 配置线程隔离:
注意,这里勾选的是并发线程数限制,也就是说这个查询功能最多使用 5 个线程,而不是 5 QPS。如果查询商品的接口每秒处理 2 个请求,则 5 个线程的实际 QPS 在 10 左右,而超出的请求自然会被拒绝。
1.5 服务熔断:
上面使用线程隔离导致了一些问题如下:
第一,超出的 QPS 上限的请求就只能抛出异常,从而导致购物车的查询失败。但从业务角度来说,即便没有查询到最新的商品信息,购物车也应该展示给用户,用户体验更好。也就是给查询失败设置一个降级处理逻辑。
第二,由于查询商品的延迟较高,从而导致查询购物车(购物车接口里面调用商品接口,涉及不同微服务之间的调用)的响应时间也变的很长。这样不仅拖慢了购物车服务,消耗了购物车服务的更多资源,而且用户体验也很差。对于商品服务这种不太健康的接口,我们应该直接停止调用,直接走降级逻辑,避免影响到当前服务。也就是将商品查询接口熔断。
1.5.1 编写降级逻辑:
触发限流或熔断后的请求不一定要直接报错,也可以返回一些默认数据或者友好提示,用户体验会更好。
给 FeignClient 编写失败后的降级逻辑有两种方式:
方式一:FallbackClass,无法对远程调用的异常做处理
方式二:FallbackFactory,可以对远程调用的异常做处理,我们一般选择这种方式。
这里我们演示方式二的失败降级处理。
涉及 ItemClient 接口,该接口是 OpenFeign 客户端。
步骤一:给ItemClient定义降级处理类,实现FallbackFactory:
代码如下:
@FeignClient(value = "item-service", configuration = DefaultFeignConfig.class, fallbackFactory = ItemClientFallback.class) public interface ItemClient { @GetMapping("/items") List<ItemDTO> queryItemByIds(@RequestParam Collection<Long> ids); @PutMapping("/items/stock/deduct") void deductStock(@RequestBody List<OrderDetailDTO> items); } // 实现FallbackFactory @Slf4j public class ItemClientFallback implements FallbackFactory<ItemClient> { @Override public ItemClient create(Throwable cause) { return new ItemClient() { @Override public List<ItemDTO> queryItemByIds(Collection<Long> ids) { log.error("远程调用ItemClient#queryItemByIds方法出现异常,参数:{}", ids, cause); // 查询购物车允许失败,查询失败,返回空集合 return CollUtils.emptyList(); } @Override public void deductStock(List<OrderDetailDTO> items) { // 库存扣减业务需要触发事务回滚,查询失败,抛出异常 throw new BizIllegalException(cause); } }; } }
@Bean public ItemClientFallback itemClientFallback(){ return new ItemClientFallback(); }
1.5.2 服务熔断:
对于不太健康的接口,我们应该停止调用,直接走降级逻辑,避免影响到当前服务。也就是将商品查询接口熔断。当商品服务接口恢复正常后,再允许调用。这其实就是断路器的工作模式了。
Sentinel中的断路器不仅可以统计某个接口的慢请求比例,还可以统计异常请求比例。当这些比例超出阈值时,就会熔断该接口,即拦截访问该接口的一切请求,降级处理;当该接口恢复正常时,再放行对于该接口的请求。
断路器的工作状态切换有一个状态机来控制:
状态机包括三个状态:
closed:关闭状态,断路器放行所有请求,并开始统计异常比例、慢请求比例。超过阈值则切换到 open 状态。
open:打开状态,服务调用被熔断,访问被熔断服务的请求会被拒绝,快速失败,直接走降级逻辑。open 状态持续一段时间后,会进入 half-open 状态。
half-open:半开状态,放行一次请求,根据执行结果来判断接下来的操作。
请求成功:则切换到 closed 状态。
请求失败:则切换到 open 状态。
我们可以在控制台通过点击簇点后的**熔断**按钮来配置熔断策略: