Sentinel 控制台介绍
Sentinel 提供一个轻量级的开源控制台,提供机器发现以及健康情况管理、监控(单机和集群)、规则管理和推送的功能:
- 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线
- 监控:通过 Sentinel 客户端暴露的监控 api,定期拉取并且聚合应用监控信息,最终可实现秒级的实时监控
- 规则管理和推送:统一管理推送规则
- 鉴权:生产环境中鉴权非常重要,根据实际情况自行定制
实时监控
监控接口通过的 QPS 和拒绝的 QPS
簇点链路
用来显示微服务所监控的 api
流控规则
流量控制(flow control)
,其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保证高可用性;同一个资源可以创建多条限流规则,FlowSlot 会对该资源的所有限流规则依次遍历,直到有规则触发限流或者所有规则遍历完毕
限流阈值类型
流量控制主要有两种统计类型,一种是统计并发线程数,另外一种则是统计 QPS;类型由FlowRule
和grade
字段来定义:0 代表根据并发数量来限流,1 代表根据 QPS 来进行限流
QPS(Query Per Second):每秒请求数,服务器在一秒的时间内能处理多少个请求
QPS
进入簇点链路选择具体的访问的 api,然后点击流控按钮:
BlockException 异常统一处理 SpringWebMVC 接口资源限流入口在 HandlerInterceptor 的实现类 AbstractSentinelInterceptor 的 preHandle 方法中,对异常的处理是 BlockExceptionHandler 的实现类
自定义 BlockExceptionHandler 的实现类统一处理 BlockException
@Slf4j
@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
log.info("BlockExceptionHandler BlockException================"+e.getRule());
R r = null;
if (e instanceof FlowException) {
r = R.error(100,"接口限流了");
} else if (e instanceof DegradeException) {
r = R.error(101,"服务降级了");
} else if (e instanceof ParamFlowException) {
r = R.error(102,"热点参数限流了");
} else if (e instanceof SystemBlockException) {
r = R.error(103,"触发系统保护规则了");
} else if (e instanceof AuthorityException) {
r = R.error(104,"授权规则不通过");
}
//返回json数据
response.setStatus(500);
response.setCharacterEncoding("utf-8");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
new ObjectMapper().writeValue(response.getWriter(), r);
}
}
并发线程数
并发数控制用于保护业务线程池不被调用耗尽;Sentinel 并发控制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目(正在执行的调用数目),若超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离;并发数控制在调用端进行配置:
流控模式
基于调用关系的流量控制;调用关系包括调用方、被调用方;一个方法可能会调用其他方法,形成一个调用链路的层次关系
直接
资源调用达到设置的阈值后直接被流控抛出异常
关联
当两个资源之间具有资源争抢或者依赖关系的时候,这个两个资源便有了关联;可使用关联限流来避免具有关联关系的资源之间过度的争抢
链路
根据调用链路入口限流
测试会发现链路规则不生效,注:高版本此功能不生效该如何解决? 从1.6.3版本开始,Sentinel Web filter默认收敛所有URL的入口context,导致链路限流不生效 从1.7.0版本开始,官方在CommonFilter引入了WEB_CONTEXT_UNIFY参数,用于控制是否收敛context,将其配置为false即可根据不同的URL进行链路限流
1.8.0 版本需要引入 sentinel-web-servlet 依赖
<!--- 解决流控链路不生效的问题-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-web-servlet</artifactId>
</dependency>
添加配置类,配置 CommonFilter 过滤器,指定 WEB_CONTEXT_UNIFY=false,禁止收敛 URL 的入口 context
@Configuration
public class SentinelConfig {
@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;
}
}
再次测试链路规则,链路规则生效但是出现异常
控制台异常:
原因分析:
- Sentinel 流控规则的处理核心是 FlowSlot,当请求 QPS 超过阈值的时候,就会触发流控规则抛出的 FlowExecption 异常
- @SentinelResource 注解模式,会在对应的 SentinelResourceAspect 切面逻辑中处理 BlockException 类型的 FlowException 异常
解决方案:
在@SentinelResource 注解中指定 BlockHandler 处理 BlockException
@Override
@SentinelResource(value = "getUser",blockHandler = "handleException")
public UserEntity getUser(int id){
UserEntity user = baseMapper.selectById(id);
return user;
}
public UserEntity handleException(int id, BlockException ex) {
UserEntity userEntity = new UserEntity();
userEntity.setUsername("===被限流降级啦===");
return userEntity;
}
流控效果
当 QPS 超过某个阈值的时候,则采取措施进行流量控制;
快速失败
RuleConstant.CONTROL_BEHAVIOR_DEFAULT
方式是默认的流控方式,当 QPS 超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出 FlowException;这种方式适用于对系统处理能力确切已知的情况下,es:通过压测确定了系统的准确水位时
Warm Up
Warm UpRuleConstant.CONTROL_BEHAVIOR_WARM_UP
方式,即预热/冷启动方式;当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮;通过”冷启动”,让系统的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮
冷加载因子:codeFactor 默认是 3,即请求 QPS 从 threshoId / 3 开始,经预热时长逐渐升至设定的 QPS 阈值
匀速排队
RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER
方式会严格控制请求通过的时间间隔,也即是让请求以均匀的速度通过,对应的是漏桶算法
这种方式主要用于处理间隔性突发的流量,es:消息队列
注:匀速排队模式暂时不支持 QPS > 1000 的场景
降级规则
除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一;需对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩;
熔断降级规则
熔断降级规则包含几个重要属性:
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名,即规则的作用对象 | |
grade | 熔断策略,支持慢调用比例/异常比例/异常数策略 | 慢调用比例 |
count | 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值 | |
timeWindow | 熔断时长,单位 s | |
minRequestAmount | 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断 | 5 |
statIntervalMs | 统计时长,单位 ms,如 60*1000 代表分钟级 | 1000 ms |
slowRatioThreshold | 慢调用比例阈值,仅慢调用比例模式有效 |
熔断策略
慢调用比例
SLOW_REQUEST_RATIO
:选择以慢调用比例作为阈值,需设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该阈值则统计为慢调用;当单位统计时长(statIntervalMs)内请求数大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时间内请求会自动被熔断
异常比例
ERROR_RATIO
:当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动化被熔断;
异常数
ERROR_COUNT
:当单位统计时长内的异常数目超过阈值之后会自动进行熔断;经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断
注:异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常不生效
热点参数限流
热点即经常访问的数据;热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流;热点参数限流可看作是一种特殊的流量控制,仅对包含热点参数的资源调用生效
注:
- 热点规则需使用 @SentinelResource(“resourceName”) 注解,否则不生效
- 参数必须是 7 种基本数据类型才会生效
具体到参数值限流:
系统规则
Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性
- Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护;当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护;系统容量由系统的
maxQps * minRt
估算得出;设定参考值一般是CPU cores * 2.5
- CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护,比较灵敏
- 平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是 ms
- 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护
- 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护
授权控制规则
很多时候,需根据调用来源判断该次请求是否允许放行,这时候可使用 Sentinel 的来源访问控制(黑白名单控制)的功能;来源访问控制根据资源的请求来源限制资源是否通过
来源访问控制规则(AuthorityRule)主要有以下配置:
- resource:资源名,即限流规则的作用对象
- limitApp:对应的黑/白名单,不同的 origin 用 ‘,’ 分割
- strategy:限制模式,AUTHORITY_WHITE 为白名单模式,AUTHORITY_BLACK 为黑名单模式,默认白名单模式
第一步:实现com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser
接口,在 parseOrigin 方法中区分来源,并交给 Spring 管理
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class MyRequestOriginParser implements RequestOriginParser {
/**
* 通过request获取来源标识,交给授权规则进行匹配
* @param request
* @return
*/
@Override
public String parseOrigin(HttpServletRequest request) {
// 标识字段名称可以自定义
String origin = request.getParameter("serviceName");
// if (StringUtil.isBlank(origin)){
// throw new IllegalArgumentException("serviceName参数未指定");
// }
return origin;
}
}
集群规则
为什么要使用集群流控呢?假设希望给某个用户限制调用某个 api 的总 QPS 为 50,但机器数可能很多(es:有 100 台);这时候很自然地就想到,找一个 server 来专门统计总的调用量,其他的实例都与这台 server 通信来判断是否可以调用;这就是最基础的集群流控的方式
集群流控可以解决流量不均匀导致总体限流效果不佳的问题;假设集群中有 10 台机器,给每台机器设置单机限流阈值为 10 QPS,理想情况下整个集群的限流阈值就为 100 QPS;不过实际情况下流量到每台机器可能不会均匀,会导致总量没有到的情况下某些机器就开始限流;因此仅靠单机维度去限制的话会无法精准的限制总体流量;而集群流控可以精确的控制整个集群的调用总量,结合单机限流兜底,可以更好的发挥流控的效果
集群流控
集群流控中共有两种身份:
- Token Client:集群流控客户端,用于向所属 Token Server 通信请求 token;集群限流服务端会返回给客户端结果,决定是否限流
- Token Server:集群控流服务端,处理来自 Toekn Client 的请求,根据配置的集群规则判断是否应该发放 token
Sentinel 集群控流支持限流规则和热点规则两种,并支持两种形式的阈值计算方式:
- 集群总体模式:限制整个集群内的某个资源的总体 QPS 不超过此阈值
- 单机均摊模式:单机均摊模式下配置的阈值等同于单机能够承受的限额,token server 会根据连接数来计算总的阈值,按照计算出的总阈值来进行限制;这种方式根据当前的连接数实时计算总的阈值,对于机器经常进行变更的环境非常适合
启动方式
Sentinel 集群限流服务端有两种启动方式:
- 独立模式(Alone):即作为独立的 token server 进程启动,独立部署,隔离性好,但是需要额外的部署操作;独立模式下适合作为 Global Rate Limiter 给集群提供流控服务
- 嵌入模式(Embedded):即作为内置的 token server 与服务在同一进程中启动;在此模式下,集群中各个实例都是对等的,token server 和 client 可以随时进行转变,因此无需单独部署,灵活性比较好;但是隔离性不佳,需要限制 token server 的总 QPS,防止影响应用本身;嵌入模式适合某个应用集群内部的流控