在前面两篇文章给大家介绍了 Sentinel 的功能和基本使用。现在我们继续来学习 Sentinel 控制台的基本使用,以及一些规则配置的说明。让大家能够在工作中使用 Sentinel 得心应手 (大部分理论和描述来源于官方文档和网络)。
在正文开始之前,我先说一下我的基本环境信息
jdk 1.8sentinel 1.8.0spring-boot 2.3.5.RELEASEspring-cloud Hoxton.SR8spring-cloud-alibaba 2.2.5.RELEASE
控制台简介
Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。这里,我们将会详细讲述如何通过简单的步骤就可以使用这些功能。
Sentinel 控制台包含如下功能:
- 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。
- 监控 (单机和集群聚合):通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。
- 规则管理和推送:统一管理推送规则。
- 鉴权:生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。
注意:Sentinel 控制台目前仅支持单机部署。Sentinel 控制台项目提供 Sentinel 功能全集示例,不作为开箱即用的生产环境控制台,若希望在生产环境使用需要自行定制和改造。
Alibaba 提供了企业版本的 Sentinel 我们可以在 aliyun.com 上面购买 AHAS Sentinel
查看机器列表以及健康情况
如果我们正确的接入 Sentinel 之后我们可以在 Sentinel 控制台的 机器列表 菜单中来查看我们服务节点的健康情况
stock-service
机器列表实例总数2,健康1,失联1.
关键字
健康状态
IP地址
Sentinel客户端版本
操作
心跳时间
端口号
机器名
2021/05/1614:07:51
172.20.10.3
健康
1.8.0
8721
54c787867b71.local
1.8.0
8722
2021/05/1614:05:04
172.20.10.3
失联
54c787867b71.local
移除
共2条记录,每页
条记录,第1/1页
10
如果 Sentinel 接入不成功,可以查阅 Sentinel 官方文档或者 FAQ 来对应排查
服务监控
1. 实时监控
同时,同一个服务下的所有机器的簇点信息会被汇总,并且秒级地展示在"实时监控"下。
注意: 实时监控仅存储 5 分钟以内的数据,如果需要持久化,需要通过调用实时监控接口来定制。
order-service
实时监控
升序
关键字
Lerror
响应时间(ms)
通过QPS
时间
拒绝QPS
0.8
3.0
14:14:57
1.0
0.0
0.6
5.0
14:14:54
1.0
0.0
0.4
14:14:51
0.0
5.0
1.0
0.2
14:14
14:14
14:14
14:14
14:14
14:14
通过QPS-拒绝QPS
注意:请确保 Sentinel 控制台所在的机器时间与自己应用的机器时间保持一致,否则会导致拉不到实时的监控数据。
2. 簇点链路
簇点链路(单机调用链路)页面实时的去拉取指定客户端资源的运行情况。它一共提供两种展示模式:一种用树状结构展示资源的调用链路,另外一种则不区分调用链路展示资源的实时情况。
注意: 簇点链路监控是内存态的信息,它仅展示启动后调用过的资源。
列表视图
树状视图
order-service
康点链路
刷新
关键字
172.20.10.3:8720
通过QPS
资源名
分钟拒绝
操作
拒绝QPS
线程数
平均RT
分钟通过
0
0
0
0
0
sentineldefault.context
降级
+授权
热点
流控
0
0
0
0
sentinelspring_web.context
授权
降级
热点
流控
产
0
0
0
0
0
授权
流控
降级
热点
o
0
0
0
0
0
/error
流控
授权
降级
热点
0
0
0
0
0
0
hello
+降级
授权
流控
热点
0
0
0
0
0
/hello1
降级
授权
热点
流控
0
0
0
GEThttp://stock-service/getStocDetall
0
授权
降级
热点
流控
0
0
0
0
0
0
hello2
授权
流控
降级
热点
o
0
0
0
0
0
GEThttp://stock-service
流控
热点
授权
降级
条记录
共9条记录,每页
16
注意:请确保 Sentinel 控制台所在的机器时间与自己应用的机器时间保持一致,否则会导致拉不到实时的监控数据。
3 流控规则
流量控制(flow control),其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
FlowSlot 会根据预设的规则,结合 NodeSelectorSlot、ClusterBuilderSlot、StatisticSlot 统计出来的实时信息进行流量控制。
新增流控规则
资源名
lgetStockDetail
针对来源
default
单机阁值
闹值类型
单机阁值
线程数
QPS
是否集群
流控模式
关联
直接
链路
流控效果
快速失败
排队等待
WarmUp
关闭高级选项
新增
新增并继续添加
取消
限流的直接表现是在执行 Entry nodeA = SphU.entry(resourceName) 的时候抛出 FlowException 异常。FlowException 是 BlockException 的子类,您可以捕捉 BlockException 来自定义被限流之后的处理逻辑。
Sentinel 在触发规则保护时,返回的异常页面是一样的。不好区分是因为哪种规则导致的异常。所以需要自定义异常返回信息,明确是触发了哪种类型的规则。
@Component public class SentinelBlockHandler implements BlockExceptionHandler { @Override public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception { CommonResult<Void> result = new CommonResult<>(); if (e instanceof FlowException) { result = CommonResult.error(101, "接口限流了"); } else if (e instanceof DegradeException) { result = CommonResult.error(102, "服务降级了"); } else if (e instanceof ParamFlowException) { result = CommonResult.error(103, "热点参数限流了"); } else if (e instanceof SystemBlockException) { result = CommonResult.error(104, "系统规则(负载/...不满足要求)"); } else if (e instanceof AuthorityException) { result = CommonResult.error(105, "授权规则不通过"); } // http状态码 httpServletResponse.setStatus(500); httpServletResponse.setCharacterEncoding("utf-8"); httpServletResponse.setHeader("Content-Type", "application/json;charset=utf-8"); httpServletResponse.setContentType("application/json;charset=utf-8"); // spring mvc自带的json操作工具,叫jackson new ObjectMapper().writeValue(httpServletResponse.getWriter(), result); } }
效果如下:
➜ curl http://127.0.0.1:8088/getStockDetail {"code":1,"message":"this is a success message","data":{"id":1,"code":"STOCK==>1000"}}% ➜ curl http://127.0.0.1:8088/getStockDetail {"code":1,"message":"this is a success message","data":{"id":1,"code":"STOCK==>1000"}}% ➜ curl http://127.0.0.1:8088/getStockDetail {"code":101,"message":"接口限流了","data":null}%
阈值类型
线程数
并发数控制用于保护业务线程池不被慢调用耗尽。例如,当应用所依赖的下游应用由于某种原因导致服务不稳定、响应延迟增加,对于调用者来说,意味着吞吐量下降和更多的线程数占用,极端情况下甚至导致线程池耗尽。为应对太多线程占用的情况,业内有使用隔离的方案,比如通过不同业务逻辑使用不同线程池来隔离业务自身之间的资源争抢(线程池隔离)。这种隔离方案虽然隔离性比较好,但是代价就是线程数目太多,线程上下文切换的 overhead 比较大,特别是对低延时的调用有比较大的影响。Sentinel 并发控制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目(正在执行的调用数目),如果超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。并发数控制通常在调用端进行配置。
新增流控规则
资源名
IgetStockDetail
default
针对来源
阅值类型
单机闽值
5
线程数
OQPS
是否集群
流控模式
O关联
链路
直接
关闭高级选项
新增并继续添加
新增
取消
可以通过线程池模拟客户端调用, 也可以通过 Jmeter 模拟,触发流控的结果如下:
➜ ~ curl http://127.0.0.1:8088/getStockDetail {"code":101,"message":"接口限流了","data":null}%
流控模式
调用关系包括调用方、被调用方;一个方法又可能会调用其它方法,形成一个调用链路的层次关系。
直接
当资源触发流控规则过后直接,抛出异常信息
➜ ~ curl http://127.0.0.1:8088/getStockDetail {"code":101,"message":"接口限流了","data":null}%
关联
当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。比如对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写的速度,写的速度过高会影响读的速度。如果放任读写操作争抢资源,则争抢本身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢,举例来说,read_db 和 write_db 这两个资源分别代表数据库读写,我们可以给 read_db 设置限流规则来达到写优先的目的:设置 strategy 为 RuleConstant.STRATEGY_RELATE 同时设置 refResource 为 write_db。这样当写库操作过于频繁时,读数据的请求会被限流。
新增流控规则
资源名
lgetStockDetail
default
针对来源
阅值类型
单机间值
QPS
线程数
当前资源
如果关联资源到达回值,
是否集群
触发流控
流控模式
直接
关联
链路
关联资源
/hello
流控效果
快速失败
排队等待
WarmUp
关闭高级选项
新增
取消
新增并继续添加
如果配置流控规则为关联模式,那么当 /hello 接口超过阈值过后,就会对 /getStockDetail 接口触发流控规则。
链路
NodeSelectorSlot 中记录了资源之间的调用链路,这些资源通过调用关系,相互之间构成一棵调用树。这棵树的根节点是一个名字为 machine-root 的虚拟节点,调用链的入口都是这个虚节点的子节点。
一棵典型的调用树如下图所示:
machine-root
/ \
/ \
Entrance1 Entrance2
/ \
/ \
DefaultNode(nodeA) DefaultNode(nodeA)
上图中来自入口 Entrance1 和 Entrance2 的请求都调用到了资源 NodeA,Sentinel 允许只根据某个入口的统计信息对资源限流。比如我们可以设置 strategy 为 RuleConstant.STRATEGY_CHAIN,同时设置 refResource 为 Entrance1 来表示只有从入口 Entrance1 的调用才会记录到 NodeA 的限流统计当中,而不关心经 Entrance2 到来的调用。
调用链的入口(上下文)是通过 API 方法 ContextUtil.enter(contextName) 定义的,其中 contextName 即对应调用链路入口名称。详情可以参考 ContextUtil 文档。]
新增流控规则
GET:http://stock-service/getStockDetail
资源名
针对来源
default
单机阁值
阅值类型
线程数
QPS
如果存在多个资源调用当前资源GET:XXX
是否集群
只有当/gntStockDetail
etail调用触发回值才流控
流控模式
?关联
直接
链路
入口资源
lgetStockDetail
流控效果
快速失败OWarmUp
排队等待
关闭高级选项
新增并继续添加
取消
新增
测试会发现 链路 不会生效
从1.6.3版本开始,Sentinel Web filter默认收敛所有URL的入口context,因此链路限流不生效。1.7.0版本开始(对应SCA 2.1.1.RELEASE),我们在CommonFilter引入了WEB_CONTEXT_UNIFY这个init parameter,用于控制是否收敛context。将其配置为false即可根据不同的URL进行链路限流。参考:https://github.com/alibaba/sentinel/issues/1213
解决方案:
1.7.0 版本开始(对应Spring Cloud Alibaba的2.1.1.RELEASE) 需要新增依赖
@Configuration public class FilterContextConfig { @Bean public FilterRegistrationBean sentinelFilterRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new CommonFilter()); registration.addUrlPatterns("/*"); // 入口资源关闭聚合 registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false"); registration.setName("sentinelFilter"); registration.setOrder(1); return registration; } }
然后我们再尝试触发流控规则, 对 /getStockDetail 进行访问,这里返回了FlowException
544---[nio-8066-exec-9]c.s.o
2021-05-1616:10:42.408ERROR18544
com.alibaba.cspentinkowEcetionn
[nio-8066-exec-ijc.so
2021-05-1616:10:42.686ERROR18544
com.alibaba.csp.entinwwxcetionu
[nio-8066-exec-2]c.s.of
2021-05-1616:10:42.767ERROR18544
com.atibabacpic
2021-0-1616:10:429
com.atibabacpici
默认情况会返回
127.0.0.1
WhitelabelErrorPage
Thisapplicarionhasnocxplicitmpingo/eoinghilck
SunMay1616:23:30CST2021
Therewasanunexpectederror(type-InternalServerError,status-5.
如果我们使用 OpenFeign 不添加 fallbackFactory 就会返回500 , 如果我们添加了就可以避免这个问题。
// Controller @Autowired private StockFeign stockFeign; @GetMapping("/getStockDetail") public CommonResult<StockModel> getStockDetail() { CommonResult<StockModel> result = stockFeign.getStockDetail(); if (result.getCode() != 1) { return CommonResult.error(null, result.getCode(), result.getMessage()); } return result; } // FeignClient @FeignClient(name = "stock-service") //, fallbackFactory = StockFeignFallbackFactory.class) public interface StockFeign { @GetMapping("/getStockDetail") CommonResult<StockModel> getStockDetail(); }
Sentinel 部分源码:
SentinellnvocationHandler.java
TesutMtHOAN
107
108
catch(Throwableex)
"ComALibabacP
109
ex:
/faiibackhandle
110
i(!BLockException.iBLockException(ex))
111
ex:"com.aLibaba.cpeninckowFowExce
Tracer.trace(ex);
112
113
if
(faltbackFactory
114
alibackFactory:
nutt
nul1)
115
objectfaltbackResult
116
faLtbackMethodMap.ge(meho)
invoke(faitbackFactory.crete(ex),
117
118
returnfaltbackResutt;
119
catch(ILLegalaccessExceptione)
120
121
happenasmethodispublicduetobeinga
mshouldnth
/interface
122
thrownewassertionerror(e);
123
124
catch(InvocationTargetExceptione)
125
thrownewassertionerror(e.getcause)
126
127
P
128
else
129
所以,我们在设置链路流控规则的时候一定要设置 fallbackFactory。不然无法处理 FlowExecption 异常信息,造成系统出错。对于个人而言,Sentinel 的链路规则比不是特别的好用,无特殊要求,不建议使用,或者选择Sentinel 的收费版本 AHAS









