雪崩问题
某一个微服务的故障,出现阻塞,把服务器资源耗尽,导致整个集群故障。
代码,网络,高并发做好。
雪崩问题解决方案
请求限流
限制微服务的请求的并发量,避免出现故障。
线程隔离
服务熔断
Sentinel
下载sentinel的jar包,然后命名为sentinel-dashboard.jar。记得放在非中文目录
在控制台运行
java "-Dserver.port=8090" "-Dcsp.sentinel.dashboard.server=localhost:8090" "-Dproject.name=sentinel-dashboard" -jar sentinel-dashboard.jar
访问localhost:8090
账号与密码都是sentinel
微服务整合sentinel
首先我们对购物车引入依赖cart-service
<!--sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
在application.yaml中添加上sentinel的地址
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8090 #sentinel控制台地址
然后对cart-service进行任意接口的调用,就可以实现实时监控。
簇点链路
所谓簇点链路,就是单机调用链路,是一次请求进入服务后经过的每一个被Sentinel
监控的资源。默认情况下,Sentinel
会监控SpringMVC
的每一个Endpoint
(接口)。
因此,我们看到/carts
这个接口路径就是其中一个簇点,我们可以对其进行限流、熔断、隔离等保护措施。
不过,需要注意的是,我们的SpringMVC接口是按照Restful风格设计,因此购物车的查询、删除、修改等接口全部都是/carts
路径。
所以我们需要将请求方式与路径结合,不让其混为一谈。
在application.yaml中加上
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8090
http-method-specify: true # 开启请求方式前缀
请求限流
在簇点链路后面点击流控按钮,即可对其做限流配置:
在弹出的菜单中这样填写:
这样就把查询购物车列表这个簇点资源的流量限制在了每秒6个,也就是最大QPS为6.
我们利用Jemeter做限流测试,我们每秒发出10个请求:
最终监控结果如下:
可以看出GET:/carts
这个接口的通过QPS稳定在6附近,而拒绝的QPS在4附近,符合我们的预期。
线程隔离
跟上面操作其实基本一样,只不过是选择并发线程数
降级逻辑
触发限流或熔断后的请求不一定要直接报错,也可以返回一些默认数据或者友好提示,用户体验会更好。
实现步骤如下:
第一步,先把cart-service的application.yaml改了
feign:
okhttp:
enabled: true
sentinel:
enabled: true
第二步,在hm-api下client下创建fallback包,并创建
ItemClientFallbackFactory类
//在hm-api模块中给ItemClient定义降级处理类,实现FallbackFactory
@Slf4j
public class ItemClientFallbackFactory 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
@Bean//编写降级熔断逻辑
public ItemClientFallbackFactory itemClientFallback(){
return new ItemClientFallbackFactory();
}
第四步,在对应的 Client上加上
服务熔断
我们利用线程隔离对查询购物车业务进行隔离,保护了购物车服务的其它接口。由于查询商品的功能耗时较高(我们模拟了500毫秒延时),再加上线程隔离限定了线程数为5,导致接口吞吐能力有限,最终QPS只有10左右。这就导致了几个问题:
第一,超出的QPS上限的请求就只能抛出异常,从而导致购物车的查询失败。但从业务角度来说,即便没有查询到最新的商品信息,购物车也应该展示给用户,用户体验更好。也就是给查询失败设置一个降级处理逻辑。
第二,由于查询商品的延迟较高(模拟的500ms),从而导致查询购物车的响应时间也变的很长。这样不仅拖慢了购物车服务,消耗了购物车服务的更多资源,而且用户体验也很差。对于商品服务这种不太健康的接口,我们应该直接停止调用,直接走降级逻辑,避免影响到当前服务。也就是将商品查询接口熔断。