微服务保护Sentinel
目标
了解雪崩产生的原因及常见解决方案
能够完成Sentinel部署并整合微服务
能够实现Sentinel限流效果(三种模式+三种效果)
能够完成Feign整合Sentinel
了解线程隔离实现方案,了解Sentinel断路器状态机流转
能够完成Sentinel线程隔离和熔断降级
能够实现Sentinel授权规则(黑白名单)
了解Sentinel规则持久化的三种方案,push模式实现步骤
前言
应用的硬件、软件架构在涉及到部署时,一般会根据实际请求量做一定的压力测试,以测试系统稳定性、健壮性,避免后续线上未知故障。 假设在一个电商的秒杀场景下,订单中心本身能够承载的QPS预设是10W,因为活动的火爆导致流量瞬时达到100W,此时订单中心因无法承载其10倍的请求将会崩溃,那么对于整个分布式架构系统会产生什么问题呢? 本节我们将借助于Sentinel的流量控制、隔离降级来解决上述分布式架构中常见的雪崩问题。
1.雪崩问题及解决方案
1.1 什么是雪崩问题
在微服务医疗系统中,当医生给患者开立药品医嘱时,需要完成对药品库存的扣减、新医嘱信息的创建、医疗费用的预扣等多个业务活动。 假设此时费用中心服务宕机,此时医嘱创建请求会持续等待下游服务的响应,在系统未做任何保护时,请求会在响应之前持续等待,随着更多的请求过来直至医嘱中心服务资源耗尽。 费用中心不可用的现象转移到其上游医嘱中心,医嘱中心的不可用随着更多的请求继续向上转移到医生站,最终导致所有服务不可用。
这种在微服务调用链路中,因为某个服务不可用导致上游服务调用者不可用,最终扩大至整个服务集群产生不可用的问题称之为雪崩效应(一个不可用导致全部不可用)。
医嘱开立逻辑
医嘱创建响应
医生
医生站
医嘱中心
药品库存中心
开立医嘱
费用中心
参数合规性校验
4.出参数据组装
库存扣减响应
1.库存扣减请求
2.医嘱创建请求
3.费用克扣请求
费用克扣响应
开立响应
1.2 造成雪崩问题的原因
造成服务不可用的原因有很多,从硬件、软件的角度都可以大致给出一些故障现场,如硬件:机房故障、网线断开等,软件:流量过载、缓存击穿等。 当服务提供者不可用,往往都会出现大量重试的情况:用户重试、代码逻辑重试、MQ重试,这些重试会进一步导致流量增加,加剧了服务雪崩的最终产生。
所以导致雪崩效应的根本原因是:大量同步请求等待造成的资源耗尽,一旦资源耗尽服务调用者提供的服务也处于不可能用砖,于是服务雪崩效应产生。 既然有问题肯定也有解决方案,目前通用的解决方案具体如下:
1.3 雪崩问题的解决方案
1 超时处理
针对服务调用增加超时机制(一般dubbo默认30s),一旦超时自动释放资源,因释放资源较快一定程度可抑制资源耗尽问题。 但如果在超时释放的时间内陡增大量请求,依然会导致服务宕机不可用。
2 舱壁模式
限定每个业务能使用的线程数,避免耗尽整个tomcat的资源,因此也叫线程隔离。 它可以避免因部分服务不可用导致整个服务不可用的问题,但是也会存在线程资源浪费的问题了。
3 熔断降级
由断路器统计业务执行的异常比例,如果超出阈值则会熔断该业务,拦截访问该业务的一切请求。 断路器会统计指定服务的请求数异常比例、异常数:
当发现异常比例、异常数超过配置的阈值时,断路器开始生效,拦截访问下游服务D的一切请求,形成熔断。
4 流量控制
相较于上述的针对已发生情况的自下而上的处理,实际更推荐自上而下的处理方案,这种方案将借助于Sentinel的流控功能去处理,拦截所有的请求,只释放服务能处理的粒度,从而保证服务的稳定性。
1.4 总结
截止此我们学到了两个重要的知识点:
什么是雪崩问题? 造成雪崩的根本原因是什么?
解决雪崩的常见解决方案:
保护:流量控制
解决:超时处理、舱壁模式、熔断降级
- 哨兵
2.1 常见微服务保护技术对比
既然上面我们分析了种种方案,那么对应这些方案又有哪些技术可以去落地呢? 目前能结合SpringCloud支持微服务保护的技术一般是:Hystrix、Sentinel,在此我们横向比对下面两种常见技术:
对比指标
哨兵
HyStrix
隔离策略
信号量隔离
线程池隔离/信号量隔离
熔断降级策略
慢调用比例/异常比例/异常数
失败比率
实时指标实现
滑动窗口
滑动窗口(基于RxJava)
规则配置
支持多种数据源
支持多种数据源
扩展性
多个扩展点
插件形式
基于注解的支持
支持
支持
限流
基于QPS、支持基于调用关系的限流
优先的支持
流量整形
支持冷启动、排队等待模式
不支持
系统自适应保护
支持
不支持
控制台
开箱即用、可配置规则、查看秒级监控、机器发现等
不完善
常见框架适配
Servlet、SpringCloud、Dubbo、gRPC等
Servlet、SpringCloud Netflix
在种种差异中,我们重点关注红色标注的部分:
隔离策略
线程池隔离:同上述线程隔离案例,给不同业务分配不同线程池,这种方案可以杜绝雪崩问题; 但是因为tomcat之外的线程池开销也使得系统开销增加,频繁的上下文切换将给系统性能带来额外的损失。
信号量隔离:不会给业务单独创建线程池(统一使用tomcat一个容器),而是限制每个业务能使用的线程数量。 统计当前业务使用的线程数,当达到指定数量后(类似计数器)触发隔离。 相较于线程池隔离性差一点。
熔断降级策略
慢调用比例/异常比例/异常数:统计调用中慢性能的比例、异常的比例、或异常数量均可触发熔断降级。
失败比例:只能根据异常请求比例触发熔断降级策略。
限流
基于QPS/调用链路:基于调用的QPS、调用链路都可以做到限流。
有限的控制:没有专门的限流方案,基于线程池隔离做的,线程池有多少线程数就限制到多少。
流量整形
慢调用/排队等待:避免突发流量的暴增而引起系统崩溃,而Hystrix则没有解决方案
控制台
Sentinel有较为完善的控制台,界面化操作实时生效,而Hystrix只能查看一下服务状态,不可动态调整。
对比可以发现Hystrix的重点在于隔离、熔断为主的容错机制,而Sentinel的侧重点在于:多样化的流量控制、熔断降级、系统保护、实时监控和控制台。 同时基于HyStrix停止维护,加上Sentinel在阿里巴巴经过双十一的高峰流量验证,目前国内主流保护还是选择了后者。 因为后续的章节中我们也将借助于Sentinel为大家实践微服务保护相关的知识点。
2.2 Sentinel介绍
Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量控制、流量路由、熔断降级、系统自适应保护等多个维度来帮助用户保障微服务的稳定性。
丰富的应用场景:阿里巴巴 10 年双十一积累的丰富流量场景,包括秒杀、双十一零点持续洪峰、热点商品探测、预热、消息队列削峰填谷等多样化的场景
易于使用快速接入:简单易用,开源生态广泛,针对 Dubbo、Spring Cloud、gRPC、Zuul、Reactor、Quarkus 等框架只需要引入适配模块即可快速接入
多样化的流量控制:资源粒度、调用关系、指标类型、控制效果等多维度的流量控制
可视化的监控和规则管理:简单易用的 Sentinel 控制台
2.3 Sentinel本地安装与启动
相较于前面Nacos的下载、shell指令的启动,Sentinel为开发者提供开箱即用的jar包,您可以从 release 页面 下载最新版本的控制台 jar 包。 也可以直接使用提供的:
sentinel-dashboard-1.8.4.jar.zip
(19.5 MB)
注意:启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本; jar包需放在非中文路径下
使用指令启动:java-en sentinel-dashboard.jar
Sentinel同时支持其余配置项来修改启动端口、用户名、密码:
配置项
默认值
说明
server.port
8080
服务端口
server.dashboard.auth.username
哨兵
默认用户名
server.dashboard.auth.password
哨兵
默认密码
如修改启动端口则可使用下述指令:
启动后访问控制台:http://localhost:8080/#/login,账户密码均为:sentinel
2.4 服务整合Sentinel
1 引入Sentinel依赖
在order-service服务中新增sentinel的pom依赖,如下:
2 配置控制台
3 访问验证
注意:服务启动依赖Nacos,需先将Nacos启动:startup.cmd -m standalone
访问order-service服务任意接口:http://localhost:8088/order/101,去控制台实时监控即可查看如下:
3.流量控制
前面我们在给出解决方案(流量控制、熔断降级、线程隔离、超时处理)时,引出Sentinel这一技术选型,那么Sentinel是如何做到的呢? 在一个调用链路中既然要实现上述方案,必然需要针对调用链路进行监控,从某一个端点对流量做拦截、隔离等处理,这一个链路特征我们叫做:簇点链路。
Sentinel监控SpringMVC的每一个端点(Endpoint),因此SpringMVC的每一个端点(Endpoint)就是调用链路中的一个资源。 请求进入微服务时,访问DispatcherServlet,然后进入Controller、Service、Mapper,这样的一个调用链就叫做簇点链路。 簇点链路中被监控的每一个接口就是一个资源。 关于资源的进一步了解:跳转
以上述访问链路为例,其端点对应的就是:/order/{orderId}
后续我们的流控、熔断都将针对簇点链路中的资源进行发起。 上面操作对应的规则汇总如下:
流控:流量控制
降级:熔断降级
热点:热点参数限流,限流的一种特殊使用场景
授权:请求的权限控制
3.1 快速上手
点击编辑资源 /order/{orderId} 的流控按钮
弹出表单如下,我们填写单机阈值:1,其含义是:限制资源/order/{orderId} 的QPS为1,即每秒只允许一次请求,超过的请求会被拦截并报错。
当我们快速刷新浏览器时,会发现出现下述错误信息
但一般来说生产的流量要更多,此处我们将借助于一个压测工具:Jmeter做更为全面的压力测试。
1 新增限流规则
新增一个流控规则,其QPS为5:
2 利用jmeter测试
开始压测之前,对于未使用过Jmeter的可以参考:Jmeter快速入门
导入提供的测试样例:
sentinel测试.jmx
(38 KB)
,步骤如下:
确认一下:“流控入门,QPS<5”的请求路径、端口是否与自己本地一致 此规则如下:20个请求在2s内执行完成,此时生效的限流规则上面我们配置的为5(每秒最多5个请求通过) 右键启动运行 运行启动后会发现每秒能通过的请求最多5个(如下展示可能会乱序,以请求时间为准): 此时,我们就完成了流量控制的入门效果,这一效果也是流控模式之一的直接模式。 3.2 流控模式 在上面的入门案例之后,我们已经实践了流控模式之一的直接模式,接下来我们将针对剩下的逐一实践。 1 直接模式 直接模式是什么 直接模式:针对当前资源的请求,触发阈值时就对当前资源直接限流,也是默认的模式。 直接模式适用于什么场景 对于没有明显差异、特殊化场景的都可以采用直接模式,它更简单易用 直接模式如何实现 参照上述:3.1 快速上手 2 关联模式 关联模式是什么 关联模式:统计与当前资源相关的另一个资源(相关或竞争),触发阈值时对当前资源限流 关联模式适用于什么场景 在一个商城系统中,用户支付时需要修改订单状态,同时用户需要查询订单。查询和修改操作会争抢数据库锁(读速过高影响写、写速过高影响读速度),争抢本身带来的开销会降低整体吞吐量。此时我们需要优先保证修改订单的功能,对查询对单业务限流。即当A触发条件时,被关联的资源B产生限流。 关联模式如何实现 针对上述场景,我们可以建立新的关联规则如下: 其规则含义为:当访问:/write接口的资源量触发阈值时(write有自己的流控规则)对:/read限流,从而避免对:/write资源的影响。下面我们结合实际案例来展开代码的实际编写。 在OrderController中新建两个端点(http接口):/order/query 和 /order/update,不用实现具体细节 配置流控规则,当 /order/update 资源被访问的QPS超过5时,对 /order/query 请求限流 步骤一: 定义/order/query 端点,模拟订单查询 步骤二: 定义/order/update 端点,模拟订单更新 步骤三: 重启OrderApplication应用后,浏览器访问端点:http://localhost:8088/order/query、http://localhost:8088/order/update,访问Sentinel控制台,查看到新的端点信息: 配置流控规则如下: 需注意:我们是针对谁做限流,就点击对应资源的流控按钮,此处我们针对:/order/query 步骤四: Jmeter压测验证,持续时长100s,qps=10,目的是持续造成超过配置阈值的窗口期,给用户访问验证的时间 运行后我们浏览器访问:http://localhost:8088/order/query,发现限流成功: 3 链路模式 链路模式是什么 链路模式:针对从指定链路访问到本资源的请求做统计,判断是否超过阈值 链路模式适用于什么场景 作为业务开发人员,我们有一个订单查询业务,同时输出做页面展现,访问链路:自身系统Controller-->查询订单接口。此时数据团队需要依赖我们的接口做驾驶舱信息,因为我们将查询订单接口暴露给别的团队,即新增一条访问链路:数据团队Controller-->查询订单接口。
自身系统的QPS我们根据压测做过合理评估,但是数据团队的请求我们并未考虑,假设有上万的请求过来,我们自身的系统性能也将收到明显影响。此时我们就需要将来自数据团队的调用加上限流。如下:
链路模式如何实现
步骤一:OrderService中添加一个queryGoods方法
步骤二:OrderController中,改造/order/query端点,调用OrderService中的queryGoods方法
步骤三:OrderController中添加一个/order/save的端点,调用OrderService的queryGoods方法
步骤四:给queryGoods设置限流规则,从/order/query进入queryGoods的方法限制QPS必须小于2
注意:设置规则之前同样需要访问才会产生簇点链路,才可以针对性设置规则,因此需要重启服务+访问新接口
步骤五:启动Jmeter压测,预期/oder/save不受影响,而/order/query最多允许放行流量=2
3.3 流控效果
1 快速失败
快速失败是什么
快速失败:针对超出限流规则配置阈值的请求,直接拦截并抛出异常
快速失败适用于什么场景
对于无特殊场景都可以采用快速失败
快速失败如何实现
参见上述:3.1 快速上手
2 Warm up(预热模式)
预热模式是什么
预热模式:应对服务冷启动的一种方案,对超出阈值的请求同样是拒绝并抛出异常。但这种模式阈值会动态变化,从一个较小值逐渐增加到最大阈值。
请求阈值初始值是 threshold / coldFactor,持续指定时长后,逐渐提高到threshold值。而coldFactor的默认值是3.例如,设置QPS的threshold为10,预热时间为5秒,那么初始阈值就是 10 / 3 ,也就是3,然后在5秒后逐渐增长到10。
预热模式适用于什么场景
对于大型分布式系统而言,应用启动之初需要连接多个中间件信息,此时如果大量的请求涌入,可能会让应用直接崩溃,从而无法保障系统的稳定性。对于这种模式下我们往往会采用预热模式,给系统一个缓冲时间。
油炸小波2023-08-07 09:521311
3
IP 属地浙江
举报
分享到:
全部评论 (3)
全部人员
赚钱去植发
赚钱去植发
2023-05-08 15:31
IP 属地广东
引用原文:在上面的入门案例之后,我们已经实践了流控模式之一的直接模式,接下来我们将针对剩下的逐一实践。
补充个人理解,便于本人做笔记使用:
在sentinel中,添加限流规则时,点击高级选项。可以选择三种流控模式(以表的形式进行比较)
统计
限制(对象)(当统计的结果触发事先设定的阈值时)
直接
当前资源
当前资源
关联
相关的另一资源
当前资源
链路
指定链路访问到本资源请求
指定链路
链路(之前的知识点):
Sentinel监控SpringMVC的每一个端点(Endpoint),因此SpringMVC的每一个端点(Endpoint,可以通俗理解为controller层的每个方法)就是调用链路中的一个资源。请求进入微服务时,访问DispatcherServlet,然后进入Controller、Service、Mapper,这样的一个调用链就叫做簇点链路。簇点链路中被监控的每一个接口就是一个资源(可以通俗理解为controller层的每个方法)
想要Service、Mapper中的方法也被当作资源,可以配上sentinel定义的注解。
赚钱去植发
赚钱去植发
2023-05-08 15:38
IP 属地广东
引用原文:在一个商城系统中,用户支付时需要修改订单状态,同时用户需要查询订单。查询和修改操作会争抢数据库锁(读速过高影响写、写速过高影响读速度),争抢本身带来的开销会降低整体吞吐量。此时我们需要优先保证修改订单的功能,对查询对单业务限流。即当A触发条件时,被关联的资源B产生限流。
个人做笔记使用:
关联模式:其他资源与本资源做竞争时,可以降低本资源的有优先级。
MiRai
MiRai
11-05 12:29
IP 属地广东
链路模式写的有点粗糙,我在网上找到的做法是
纯文本
复制代码
1
2
3
4
@SentinelResource("goods")
public void queryGoods() {
System.out.println("查询订单成功");
}
需要在queryGoods上面添加@SentinelResource("goods")注解,告诉sentinel,goods是哪个资源,然后需要在application.yml里新增
纯文本
复制代码
1
2
sentinel:
web-context-unify: false
这样才会生效