微服务系列五:避免雪崩问题的限流、隔离、熔断措施
目录
实验环境说明
前言
一、一片小雪花引起的雪崩!
1.1 雪崩问题(级联失败问题)示意图
1.2 雪崩问题的产生原因与解决策略
二、雪崩问题的具体解决策略
2.1 请求限流
2.2 线程隔离
2.3 服务熔断
2.4 总结——具体解决策略
三、微服务保护工具:sentinel
3.1 sentinel 介绍
3.2 sentinel安装
3.3 sentinel微服务整合
3.4 簇点链路调整
四、基于sentinel实现请求限流
4.1 配置请求限流说明
4.2 请求限流实践
4.2.1 配置请求限流规则
4.2.2 JMeter并发测试
4.2.3 sentinel流控展示
五、基于sentinel实现线程隔离
5.1 模拟无线程隔离配置阻塞请求压垮服务器实验
5.1.1 配置慢请求业务
5.1.2 调整服务器资源量
5.1.3 正常请求现象展示
5.1.4 JMeter压力测试并查看接口响应情况
5.2 配置线程隔离规则
5.3 JMeter并发测试
5.4 sentinel流控效果显示
六、fallback逻辑优化
6.1 fallback实验说明
6.2 调整簇点策略,注册OpenFeign簇点
6.3 FallbackFactory配置Fallback
6.3.1 编写ItemClientFallbackFactory类
6.3.2 在Config中注册Bean对象
6.3.3 在对应的Client上添加注解使用
6.4 线程隔离 + Fallback实验测试
6.4.1 给feign簇点添加线程隔离规则
6.4.2 JMeter并发测试并查看响应结果
6.4.3 sentinel流控效果展示
七、基于sentinel实现服务熔断
7.1 断路器介绍
7.2 配置服务熔断规则说明
7.3 JMeter并发测试并进行前后对比
八、微服务保护方案相关知识追问巩固
实验环境说明
本文有部分地方需要实验进行。首先对于看过黑马微服务的同学应该会比较熟悉。如果没有你也可以参考我实验的环境搭个简单的测试环境,用于实验。实验的目的也是为了更好的理解业务、理解知识点。
本地环境部分:
服务名 | 端口号 | 备注 |
nginx | 18080 / 18081 | 前端运行环境 |
sentinel | 8090 | 服务保护监控 |
hm-gateway | 8080 | 后端项目网关模块 |
item-service | 8081 | 后端商品服务模块 |
cart-service | 8082 | 后端购物车服务模块 |
item-service2 | 8083 | 后端商品服务模块 |
item-service3 | 8084 | 后端商品服务模块 |
user-service | 8085 | 后端用户管理模块 |
trade-service | 8086 | 后端交易服务模块 |
pay-service | 8087 | 后端支付服务模块 |
远程服务器环境部分:
服务名 | 端口号 | 备注 |
nacos | 8848 | 注册中心及配置中心,非容器镜像 |
mysql | 3306 | 线上数据库,容器镜像 |
注意事项:
- 远程环境中非容器镜像指nacos是后单独配置的容器,而mysql、nginx、docker-hm是使用compose统一部署的。
- 在本节实验中,线上环境的nginx和docker-hm我们不会使用到,而是使用本地的nginx和后端项目
- 请你确保在配置线上环境时,mysql必须先比nacos启动。如果nacos先启动将无法连接数据库。此时你需要停止nacos容器,先启动mysql。
前言
先前我们依次学习了远程调用、服务治理、请求路由、身份认证、配置管理的相关知识。本篇,我们将从雪崩问题出发,去探讨微服务的保护措施及实现方法。
一、一片小雪花引起的雪崩!
1.1 雪崩问题(级联失败问题)示意图
微服务调用链路中的某个服务故障,引起整个链路中的所有微服务都不可用,这就是雪崩。
1.2 雪崩问题的产生原因与解决策略
产生原因 | 解决策略 |
服务相互调用,而服务提供者出现故障或阻塞 | 尽量避免服务提供者出现阻塞,限制请求数量【请求限流】 |
服务调用者被大量阻塞请求占满,导致服务器崩溃 | 尽量避免无节制的调用服务器资源请求异常服务,限制调用服务的线程数量【线程隔离】 |
调用链中连环失败,没有及时阻断,对于异常请求仍然不断去重试,浪费资源。 | 尽量避免对已经确认异常的服务继续发送请求,及时做到断止请求【服务熔断】 |
总结:确保服务提供者能处理它能力范围内的请求,同时服务调用者要设置好合适的线程数,以免请求占满服务器资源。最后,如果服务提供者出现大量异常后,也要及时断舍,不要再做无意义的请求去浪费资源。
二、雪崩问题的具体解决策略
2.1 请求限流
请求限流:限制访问微服务的请求的并发量,避免服务因流量激增出现故障。
2.2 线程隔离
举例:就像将船分为若干块,即使一块进水了,也不会导致整船的进水。减少对整体的影响。
线程隔离:相当于利用线程将服务器隔离成多块,即使部分异常也不会拖垮服务器,减少对服务器的影响。
fallback优化:有时候我们不希望抛出服务异常,这时我们可以让异常的服务调用变成自定义的fallback逻辑,这样一来可以快速失败,执行fallback中的业务逻辑,返回默认数据或友好提示。
2.3 服务熔断
举例:就像家庭电路中的空气开关。当电器出现漏电异常或者短路时,空气开关会自动切断电源,以免照常更多的电器损失。
服务熔断:由断路器统计请求的异常比例或慢调用比例,如果超出阈值则会熔断该业务,则拦截该接口的请求。 熔断期间,所有请求快速失败,全都走fallback逻辑。
fallback逻辑:对于需要熔断的服务,没有必要再发送请求浪费,直接熔断并且走fallback,执行服务异常时的业务逻辑。
2.4 总结——具体解决策略
请求限流 | 限制流量在服务可以处理的范围,避免因突发流量而故障 |
线程隔离 | 控制业务可用的线程数量,将故障隔离在一定范围 |
服务熔断 | 将异常比例过高的接口断开,拒绝所有请求,直接走fallback |
失败处理 | 定义fallback逻辑,让业务失败时不再抛出异常,而是返回默认数据或友好提示 |
三、微服务保护工具:sentinel
3.1 sentinel 介绍
Sentinel是阿里巴巴开源的一款微服务流量控制组件。Sentinel定位是分布式系统的流量防卫兵。目前互联网应用基本上都使用微服务,微服务的稳定性是一个很重要的问题,而限流、熔断降级是微服务保持稳定的一个重要的手段。
home | Sentinelhomehttps://sentinelguard.io/zh-cn/index.html
3.2 sentinel安装
【下载】
sentinel的下载地址 Releases · alibaba/Sentinelhttps://github.com/alibaba/Sentinel/releases 下载后放到非中文目录下,将版本后缀删除:
【运行】
打开cmd命令窗口,运行启动脚本
java -Dserver.port=8090 -Dcsp.sentinel.dashboard.server=localhost:8090 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
【访问】
本地访问 localhost:8090端口,即可进入控制台。(登录账号密码默认都是sentinel)
3.3 sentinel微服务整合
【基本步骤】
- 引入sentinel依赖
- 配置控制台发现
- 访问微服务,测试sentinel监控
以下实验以cart-service模块为例:
【引入依赖】
<!--sentinel-->
<dependency><groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
【增加配置文件】
spring:cloud: sentinel:transport:dashboard: localhost:8090
【重启测试服务】
对购物车的相关服务进行访问,查看sentinel的监控效果
3.4 簇点链路调整
簇点链路: 就是单机调用链路。是一次请求进入服务后经过的每一个被Sentinel监控的资源链。默认Sentinel会监控SpringMVC的每一个Endpoint(http接口)。限流、熔断等都是针对簇点链路中的资源设置的。而资源名默认就是接口的请求路径:
当前项目基于restful风格,还存在一些不合适的问题:
如何让每个接口都能显示出来呢?我们需要对簇点链路配置进行一些调整:
修改配置文件,添加一行配置:
spring:cloud:sentinel:transport:dashboard: localhost:8090http-method-specify: true # 开启请求方式前缀
重新上线测试:
四、基于sentinel实现请求限流
4.1 配置请求限流说明
在簇点链路后面点击流控按钮,即可对其做限流配置:
4.2 请求限流实践
以下实验以获取购物车列表接口为例:
4.2.1 配置请求限流规则
4.2.2 JMeter并发测试
4.2.3 sentinel流控展示
五、基于sentinel实现线程隔离
5.1 模拟无线程隔离配置阻塞请求压垮服务器实验
本实验以购物车列表查询接口为例:由于购物车列表需要依赖商品查询的数据,因此可以进行本次实验。(完成本次实验前,请将请求限流规则删除)
5.1.1 配置慢请求业务
将根据ID批量查询商品接口改为慢查询
5.1.2 调整服务器资源量
为了能更快展现压垮服务器的情况,我们需要把tomcat服务器默认的资源量(默认8192)改小一点。
5.1.3 正常请求现象展示
购物车列表查询速度500多毫秒,且目前正常查询到商品数据
其他购物车接口查询速度正常,10多毫秒
5.1.4 JMeter压力测试并查看接口响应情况
这一步需要在JMeter高并发请求的过程中进行。
【利用JMeter不断发送购物车列表请求,压力服务器】
【查看购物车接口的响应结果】
【更加暴力的测试】提高到每秒400并发
(哥们别测太高,电脑死机就完蛋了)
5.2 配置线程隔离规则
5.3 JMeter并发测试
5.4 sentinel流控效果显示
六、fallback逻辑优化
6.1 fallback实验说明
第五节线程隔离中存在一个问题:发现没有,控制台基本上全是报错的,但是有时后我们不希望服务抛出异常,而是在服务异常后走我们自定义的业务逻辑。这个时候就需要fallback登场了。
以查询购物车列表为例,在商品查询业务慢导致线程占满,返回请求429的情况下。我们希望还能正常显示购物车列表信息。对此,我们可以给查询逻辑添加fallback,在资源耗尽被拒绝的时候,我们直接走fallback,将单单购物车的数据展示到前端就行了(不管商品信息)
也就是说,我们不需要隔离购物车业务,而是直接隔离异常的商品查询接口!
但是,调用商品查询接口是OpenFeign调用,如何给这条链路添加上线程隔离规则呢?
我们必须先将这条链路注册成一个簇点。接下来就跟着我一起实验吧!
6.2 调整簇点策略,注册OpenFeign簇点
在cart-service模块中,开启feign对sentinel的支持
feign: sentinel:enabled: true # 开启feign对sentinel的支持
重启查看sentinel
接下来我们就可以对这个接口进行流控啦!不过在此之前我们先配置一下fallback逻辑,
给FeignClient编写失败后的降级逻辑有两种方式:
-
方式一:FallbackClass,无法对远程调用的异常做处理
-
方式二:FallbackFactory,可以对远程调用的异常做处理,我们一般选择这种方式。
6.3 FallbackFactory配置Fallback
6.3.1 编写ItemClientFallbackFactory类
在hm-api模块下新建client.fallback.itemClientFallbackFactory.java,并实现FallbackFactory接口
package com.hmall.api.client.fallback;import com.hmall.api.client.ItemClient;
import com.hmall.api.dto.ItemDTO;
import com.hmall.api.dto.OrderDetailDTO;
import com.hmall.common.utils.CollUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;import java.util.Collection;
import java.util.List;@Slf4j
public class ItemClientFallbackFactory implements FallbackFactory<ItemClient> {@Overridepublic ItemClient create(Throwable cause) {return new ItemClient() {@Overridepublic List<ItemDTO> queryItemByIds(Collection<Long> ids) {log.error("查询商品信息失败: ", cause);// 返回空集合return CollUtils.emptyList();}@Overridepublic void deductStock(List<OrderDetailDTO> items) {log.error("扣减库存失败: ", cause);throw new RuntimeException(cause);}};}
}
6.3.2 在Config中注册Bean对象
@Beanpublic ItemClientFallbackFactory itemClientFallbackFactory() {return new ItemClientFallbackFactory();}
6.3.3 在对应的Client上添加注解使用
到此为止,Fallback已经编写完成了,接下来再次进行线程隔离实验测试
6.4 线程隔离 + Fallback实验测试
6.4.1 给feign簇点添加线程隔离规则
6.4.2 JMeter并发测试并查看响应结果
查询购物车列表不报错了,而且查询从500多毫秒变成了几十毫秒
6.4.3 sentinel流控效果展示
七、基于sentinel实现服务熔断
7.1 断路器介绍
熔断是解决雪崩问题的重要手段。思路是由断路器统计服务调用的异常比例、慢请求比例,如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求;而当服务恢复时,断路器会放行访问该服务的请求。
知道服务已经挂了,就不需要再给他发请求了,直接拒绝发起请求,直接走fallback逻辑。进而节约更多的资源。与此同时,服务熔断需要有一个恢复时长,在恢复时再次请求查看是否成功。成功就结束熔断,否则继续进入熔断状态!
7.2 配置服务熔断规则说明
7.3 JMeter并发测试并进行前后对比
不加服务熔断前的状态:
加了服务熔断后的状态
超过熔断时间20s后,请求恢复正常
八、微服务保护方案相关知识追问巩固
1. 请你谈谈微服务雪崩问题是如何产生的?产生的后果是什么?
2. 对于雪崩问题,你有哪些好的解决方案呢?
3. 你知道什么是流量控制组件么?你有用过哪些微服务流量控制组件?
4. 请你谈谈sentinel如何整合到我们的微服务项目中?说出具体的步骤?
5. 关于sentinel簇点的概念?什么是簇点链路?
6. restful风格的微服务项目使用sentinel簇点需要注意什么问题?如何配置?
7. openfeign调用如何注册到sentinel的簇点链路中?
8. openfeign调用的请求如何单独给它加上流量控制规则?具体的步骤是什么?
9. 请你谈谈使用sentinel如何实现请求限流、线程隔离?
10. 请你谈谈如何编写fallback逻辑,具体的步骤是什么?
11. 请你谈谈使用sentinel如何实现服务熔断,熔断有哪些常见的策略?
12. 请你谈谈服务熔断中熔断器的工作流程,什么是熔断时长?