Sentinel
下载sentinel-dashboard-1.8.3.jar,通过命令行启动
--server.port:自定义服务器端口。默认为 8080 端口。 --auth.username 和 --auth.password:自定义账号和密码。默认为「sentinel / sentinel」。 --logging.file:自定义日志文件。默认为 ${user.home}/logs/csp/sentinel-dashboard.log。
java -jar sentinel-dashboard-1.8.1.jar --server.port=8080
添加依赖
<!-- Sentinel 核心库 --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-core</artifactId> <version>1.8.3</version> </dependency> <!-- Sentinel 接入控制台 --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-transport-simple-http</artifactId> <version>1.8.3</version> </dependency> <!-- Sentinel 对 SpringMVC 的支持 --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-spring-webmvc-adapter</artifactId> <version>1.8.3</version> </dependency> <!-- Sentinel 对 Spring AOP 的拓展 --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-annotation-aspectj</artifactId> <version>1.8.3</version> </dependency>
添加Sentinel拦截器
@Configuration public class WebConfiguration implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { addSentinelWebTotalInterceptor(registry); addSentinelWebInterceptor(registry); } private void addSentinelWebInterceptor(InterceptorRegistry registry) { SentinelWebMvcConfig config = new SentinelWebMvcConfig(); /** * 是否包含请求方法,即基于URL创建资源,是否包含Method */ config.setHttpMethodSpecify(true); /** * 设置BlockException处理器,对达到流量控制阈值后的请求处理 */ config.setBlockExceptionHandler(new MyBlockExceptionHandler()); /** * 添加SentinelWebInterceptor拦截器 */ registry.addInterceptor(new SentinelWebInterceptor(config)) .addPathPatterns("/**"); } private void addSentinelWebTotalInterceptor(InterceptorRegistry registry) { /** * 针对全局URL进行流量控制,将所有URL合计流量,全局统一控制 */ SentinelWebMvcTotalConfig config = new SentinelWebMvcTotalConfig(); registry.addInterceptor(new SentinelWebTotalInterceptor(config)).addPathPatterns("/**"); } }
Sentinel在发生blockException时,默认返回仅仅是一句Blocked by Sentinel (flow limiting)而大部分的应用一般都会统一返回一个固定json格式的数据
BlockException 是一个异常抽象基类,其有 5 个实现类,对应 Sentinel 的 5 种流量控制手段,如下图所示:

BlockException异常默认处理类
在 SentinelWebInterceptor 拦截器中,满足配置的 Sentinel block 的条件时,Sentinel 会抛出 BlockException 异常。定义 BlockExceptionHandler 接口的实现类,可以实现对 BlockException 的异常处理
默认情况下,BlockExceptionHandler 有一个默认的 DefaultBlockExceptionHandler 实现类,返回 Block 字符串提示。这个类是默认处理异常阻塞的,代码如下:
//Default handler for the blocked request public class DefaultBlockExceptionHandler implements BlockExceptionHandler { @Override public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception { // ... 省略其它代码 PrintWriter out = response.getWriter(); out.print("Blocked by Sentinel (flow limiting)"); } }
自定义BlockException异常处理
通过实现BlockExceptionHandler接口来自定义BlockException异常处理
fallback 和 blockHandler 的差异点在于, blockHandler 只能处理 BlockException 异常,fallback 能够处理所有异常。如果都配置的情况下,BlockException 异常分配给 blockHandler 处理,其它异常分配给 fallback 处理。
@Slf4j @Component public class MyBlockExceptionHandler implements BlockExceptionHandler { @Override public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception { Result result = null; if (e instanceof FlowException) { result = Result.fail(5001, "接口限流"); } else if (e instanceof DegradeException) { result = Result.fail(5002, "服务降级"); } else if (e instanceof SystemBlockException) { result = Result.fail(5003, "系统触发保护"); } else if (e instanceof AuthorityException) { result = Result.fail(5004, "权限规则失败"); } httpServletResponse.setStatus(HttpStatus.OK.value()); httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE); httpServletResponse.setCharacterEncoding("UTF-8"); httpServletResponse.getWriter().write(JSONObject.toJSONString(result)); } }
添加sentinel.properties启动配置项,指定接入控制台
csp.sentinel.dashboard.server=127.0.0.1:8080
启动类
@SpringBootApplication public class BootSentinelApplication { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(BootSentinelApplication.class, args); } }
测试类
@RestController @RequestMapping("/foo") public class FooController { @Autowired private RestTemplate restTemplate; @GetMapping("/echo") public String echo() { return "echo"; } @GetMapping("/sleep") public String sleep() throws InterruptedException { Thread.sleep(200L); return "sleep"; } }
控制台效果

流量控制(flow control)
监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。Sentinel在限流时会抛出BlockException的子类FlowException。

- 资源名(resource):限流规则的作用对象
- 针对来源(limitApp):流控针对的调用来源,为
default则不区分调用来源。通过ContextUtil.enter(resourceName, origin)方法中的origin参数标明调用方身份。当参数为{some_origin_name}时表示只有来自这个调用者的请求才会进行流量控制。other则表示除{some_origin_name} 以外的其余调用方的流量进行流量控制。 - 阈值类型(grade):QPS/并发数
并发数控制用于保护业务线程池不被慢调用耗尽。Sentinel 并发控制不负责创建和管理线程池,简单统计当前请求上下文的线程数目(正在执行的调用数目),如果超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。并发数控制通常在调用端进行配置。推荐使用QPS。 - 流控模式(strategy):调用关系限流策略,包括直接(STRATEGY_DIRECT)、关联(STRATEGY_RELATE)和链路(STRATEGY_CHAIN)
直接是limitApp中指定的origin
关联是具有竞争或依赖关系的资源,如配置写库来达到优写的目的;使用场景:比如用户支付时需要修改订单状态,同时用户要查询订单。查询和修改操作会争抢数据库锁,产生竞争。业务需求是有限支付和更新订单的业务,因此当修改订单业务触发阈值时,需要对查询订单业务限流。

当/update资源访问量触发阈值时,就会对/query资源限流,避免影响/update资源
链路指同资源下被指定的入口将被监控限流,而且其它入口则直接放行,例如有两条请求链路:
- /test1 --> /common
- /test2 --> /common
如果只希望统计从/test2进入到/common的请求,则可以这样配置:

- 流控效果(controlBehavior):由QPS限流触发,直接拒绝、Warm Up、匀速排队
直接拒绝是在打到QPS阈值时,直接抛出FlowException异常,适用于测压后确定出系统处理能力的准水位。
Warm UP为预热/冷启动,是应对服务冷启动的一种方案。请求阈值初始值是 threshold / coldFactor,持续指定时长后,逐渐提高到threshold值。而coldFactor的默认值是3. 例如,我设置QPS的threshold为10,预热时间为5秒,那么初始阈值就是 10 / 3 ,也就是3,然后在5秒后逐渐增长到10.
- 排队等待是让所有请求进入一个队列中,然后按照阈值允许的时间间隔依次执行。后来的请求必须等待前面执行完成,如果请求预期的等待时间超出最大时长,则会被拒绝。
例如:QPS = 5,意味着每200ms处理一个队列中的请求;timeout = 2000,意味着预期等待超过2000ms的请求会被拒绝并抛出异常
熔断降级
Sentinel熔断策略包括:慢调用比例(默认最大RT=4900ms)、异常比例、异常数
慢调用:业务的响应时长(RT)大于指定时长的请求认定为慢调用请求。在指定时间内,如果请求数量超过设定的最小数量,慢调用比例大于设定的阈值,则触发熔断。例如:

RT超过500ms的调用是慢调用,统计最近10000ms内的请求,如果请求量超过10次,并且慢调用比例不低于0.5,则触发熔断,熔断时长为5秒。然后进入half-open状态,放行一次请求做测试。
异常比例:统计指定时间内的调用,如果调用次数超过指定请求数,并且出现异常的比例达到设定的比例阈值,则触发熔断。
异常数:统计指定时间内的调用,如果调用次数超过指定请求数,并且出现异常的比例超过指定异常数,则触发熔断。
当【统计时长】周期内,发起的请求数大于【最小请求数】时,会根据【最大RT/比例阈值/异常数】进行熔断,窗口期为【熔断时长】

热点参数限流
根据请求的参数来做限流,比如请求带的参数是热点参数,就对这个请求应用特殊的限流规则;对携带非热点参数的请求,走另一个限流规则

- 资源名:
@SentinelResource(value = "xxx")中的value值; - 参数索引(0):针对第 0 个参数;
- 参数类型(long):索引位置是 0 的参数的类型是 long;
- 参数值(1):如果其值是 1;
- 限流阈值(1):允许的 QPS 就是 1;
- 单机阈值(10):不是 1 的情况下,允许的 QPS 就是 10;
- 统计时间窗口(1):统计的时间单位,一般都是 1s;
系统自适应限流参数

- LOAD:只有在 Linux 系统的机器上才会生效,可以根据当前操作系统的负载,来决定是否触发保护(把请求拒绝掉);
- RT:这个应用上,所有请求的平均响应时间,如果超过某个值,就停止新的请求;
- 线程数:这个应用上,所有的请求消耗的线程数加起来,如果超过某个值,就停止新的请求;
- 入口 QPS:这个应用上,所有接口的 QPS 加起来,如果超过某个值,就停止新的请求;
- CPU 使用率:CPU 的使用率,如果超过一个百分比,就停止新的请求;
浙公网安备 33010602011771号