1.什么是服务雪崩
在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用(RPC),在Spring Cloud可以用RestTemplate+Ribbon和Feign来调用。为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。
如下图所示 , A为服务提供者 , B为A的消费者 , C是B的消费者
当A服务不可用时 , 导致B服务的不可用 , 并将不可用逐渐蔓延到C , 就发生了微服务中的"雪崩"现象。
2.服务雪崩产生过程
正常情况 , 一个请求进入C , C会从线程池中申请一个线程处理 , 然后请求B , 同时线程等待 ; B服务收到请求同样申请线程然后请求A , A处理完成返程结果并归还释放A自身的线程 , 然后BC依次完成响应并归/释放还线程
A故障后 , B的线程请求A后 , 迟迟未得响应 , 线程阻塞等待
C继续接收大量请求并传给B , 导致B大量阻塞线程等待 , 直到线程资源耗尽 , 无法接收新的请求 . B服务故障
故障继续蔓延 , C的线程资源耗尽后 , 一个请求再也不能完成 . 整个微服务当机
3.服务雪崩产生原因
- 服务提供者不可用
硬件故障:服务器主机死机 , 或网络硬件故障导致服务提供者无法及时处理和相应
程序故障 : 缓存击穿 , 缓存应用重启或故障导致所有缓存被清空 , 或者大量缓存同时过期 , 导致大量请求直击后端(文件或数据库) , 造成服务提供者超负荷运行导致瘫痪 ; 高并发请求 , 在某些场景下 , 例如秒杀和大促销之前 , 如果没有做好应对措施 , 用户的大量请求也会导致服务故障 - 不合理的流量激增
用户重试 : 用户忍不了界面上的一直加载或等待 , 频繁刷新页面或提交表单 , 这是在秒杀场景下的常规操作
代码逻辑重试 : 在消费者服务中存在大量不合理的重试逻辑 , 比如各种异常的重试机制等 - 服务消费者不可用
大量的等待线程占用系统资源 , 一旦资源被耗尽 , 消费者这边也会发生连锁反应 , 然后会导致故障向下蔓延
4.雪崩的应对策略
- 硬件更新升级(花钱)
- 流量控制
- 网关限流 , 例如nginx等 , 防止大量请求进入系统
- Mq实现流量消峰
- 用户交流限流,提交按钮限制点击频率限制等
- 改进缓存模式
- 缓存预加载
- 对集中添加并且过期时间一致的缓存 , 适当的随机分配一些过期时长 , 防止集中过期
- 服务扩容
- 通过软件对服务监控 , 到达上限自动扩容
- 在特定场景下提前增加服务器
- 服务降级
- 对调用服务提供者的线程进行隔离 , 单独开辟出一个线程池(例如 , 一个商品页面 , 要展示商品信息 , 和评论信息 , 及购买记录等 , 那对每个服务的线程池都单独开辟 , 这样即使获取不到评论信息 , 那不耽误用户正常浏览商品的一些内容)
- 对依赖服务进行分类优化 ; 强依赖服务(必须请求上级并获得结果) , 强制中断该业务 , 引导重试或返回错误 , 弱依赖服务(可以不获取上级结果 , 不影响整体业务) , 跳过故障服务 , 或做个标识后续执行补救措施
- 对不可用的服务快速调用失败 . 即断路器降级方法 , 释放线程资源 , 确保服务稳定
5.服务雪崩效应解决方案
- 服务降级
- 请求缓存
- 请求合并
- 服务熔断
- 线程池隔离
- 信号量隔离
解决方案在后面的使用过程中再做详细介绍