Spring Cloud Alibaba整合Sentinel
1、引入POM文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>vnacos</artifactId> <groupId>com.nacos</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>order-sentinel</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--sentinel启动器--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
报错: Unable to create a Configuration, because no Bean Validation provider could be found. Add a provide 加下面POM文件
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.2.4.Final</version> </dependency> </dependencies> </project>
配置文件:
spring: application: name: order-sentinel cloud: sentinel: transport: dashboard: 127.0.0.1:8850 # 控制台 ip和端口
Controller层:
package com.sentinel.order.controller; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.BlockException; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.TimeUnit; /** * @author vans on 2022/2/24 11:39 */ @Slf4j @RestController @RequestMapping("/vn/sentinel") public class VnSentinelController { @GetMapping(value = "/flow") @SentinelResource(value = "flow",blockHandler = "flowBlockHandler") public String flow(){ return "正常访问"; } public String flowBlockHandler(BlockException e){ return "流控"; } @GetMapping(value = "/flowThread") @SentinelResource(value = "flowThread",blockHandler = "flowBlockHandler") public String flowThread() throws InterruptedException { TimeUnit.SECONDS.sleep(5); return "正常访问"; } }
BlockException异常统一处理(1、统一处理,将Controller层中@SentinelResource去掉;2、实现BlockExceptionHandler类)
package com.sentinel.order.interceptor.sentinel.exception; import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException; import com.alibaba.csp.sentinel.slots.block.flow.FlowException; import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException; import com.alibaba.csp.sentinel.slots.system.SystemBlockException; import com.fasterxml.jackson.databind.ObjectMapper; import com.sentinel.order.entity.Result; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Component public class SentinelException implements BlockExceptionHandler { Logger log= LoggerFactory.getLogger(this.getClass()); @Override public void handle(HttpServletRequest httpServletRequest, HttpServletResponse response, BlockException e) throws Exception { // getRule() 资源 规则的详细信息 log.info("BlockExceptionHandler BlockException================"+e.getRule()); Result r = null; if (e instanceof FlowException) { r = Result.error(100,"接口限流了"); } else if (e instanceof DegradeException) { r = Result.error(101,"服务降级了"); } else if (e instanceof ParamFlowException) { r = Result.error(102,"热点参数限流了"); } else if (e instanceof SystemBlockException) { r = Result.error(103,"触发系统保护规则了"); } else if (e instanceof AuthorityException) { r = Result.error(104,"授权规则不通过"); } //返回json数据 response.setStatus(500); response.setCharacterEncoding("utf-8"); response.setContentType(MediaType.APPLICATION_JSON_VALUE); new ObjectMapper().writeValue(response.getWriter(), r); } }
客户端启动后必须访问,在控制台才能看到数据
流控模式:(通常在服务提供短进行配置)
直接流控:
QPS流控:
线程流控:
关联流控:
链路流控:
代码实现:
------配置文件:
spring: application: name: order-sentinel cloud: sentinel: transport: dashboard: 127.0.0.1:8850 # 控制台 ip和端口 web-context-unify: false # 默认将调用链路收敛, 导致链路流控效果无效, 所以 web-context-unify: false 才可以
------Controller层:
package com.sentinel.order.controller; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.sentinel.order.service.OrderService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.TimeUnit; /** * @author vans on 2022/2/24 11:39 */ @Slf4j @RestController @RequestMapping("/vn/sentinel") public class VnSentinelController { @Autowired private OrderService orderService; // 链路流控 test1 获取订单 @RequestMapping("/test1") public String test1(){ return orderService.selectOrder(); } // 链路流控 test2 获取订单 @RequestMapping("/test2") public String test2() throws InterruptedException { return orderService.selectOrder(); } }
------Service层:
package com.sentinel.order.service.impl; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.sentinel.order.service.OrderService; import org.springframework.stereotype.Service; /** * @author vans on 2022/2/25 16:59 */ @Service public class OrderServiceImpl implements OrderService {
/**
*
* 链路流控,此场景拦截不到BlockException,对应@SentinelResource指定的资源必须在@SentinelResource注解中指定blockHandler处理BlockException
*/ @Override @SentinelResource(value="selectOrder",blockHandler = "blockHandlerSelectOrder") public String selectOrder() { return "查询订单selectOrder"; } public String blockHandlerSelectOrder(BlockException e) { return "查询订单selectOrder流控"; } }
流控效果
warmUp:预热(激增流量)
即预热/冷启动方式
当系统长期处于低水位的情况下,当流量 突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐 增加到阈值上限,给冷系统一个预热的时间,
避免冷系统被压垮。 冷加载因子: codeFactor 默认是3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值。
排队等待:(脉冲流量)
降级规则(通常在服务消费端进行配置)
---慢调用比例
慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间), 请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)
内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态 (HALFOPEN 状态),若接下来的一个请求响应时
间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会 再次被熔断


---异常调用比例
异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例 大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进
入探测恢复状态(HALFOPEN 状 态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0], 代表 0% 100%
---异常调用数
异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探 测恢复状态(HALFOPEN 状态),若接下来的一个请求成功完成(没有错误)则结束
熔断,否则会再次被熔断。 注意:异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效
---热点参数限流
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。
热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
图片解释:


代码:
/** * 热点规则,必须使用@SentinelResource * * @param id * @throws InterruptedException */ @PostMapping("/get/{id}") @SentinelResource(value = "getById",blockHandler = "HotBlockHandler") public String getById(@PathVariable("id") Integer id) throws InterruptedException { return "getById--success"; } public String HotBlockHandler(@PathVariable("id") Integer id,BlockException e) throws InterruptedException { return "getById--hotError"; }
系统规则
1、Load 自适应(仅对 Linux/Unixlike 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的
并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统 容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores * 2.5
https://www.cnblogs.com/gentlemanhai/p/8484839.html
2、CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.01.0),比较灵敏。
3、平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
4、并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
5、入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。