目录
Sentinel是一个轻量级的流量控制与熔断降级Java库。类似于Hystrix。可以处理服务使用过程中的各种问题,如服务雪崩、服务降级、服务熔断、服务限流等。

下载:下载jar包,例如sentinel-dashboard-1.7.0.jar
使用前提:Jdk8、8080端口未被占用。
开启:在jar包目录下执行下面指令。
java -jar sentinel-dashboard-1.7.0.jar
最后输入地址: http://localhost:8080 即为Sentinel的后台管理界面
1.建立新工程-cloudalibaba-sentinel-service8401
2.POM
- <dependencies>
-
- <dependency>
- <groupId>com.alibaba.cloudgroupId>
- <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
- dependency>
-
- <dependency>
- <groupId>com.alibaba.cspgroupId>
- <artifactId>sentinel-datasource-nacosartifactId>
- dependency>
-
- <dependency>
- <groupId>com.alibaba.cloudgroupId>
- <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
- dependency>
-
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-openfeignartifactId>
- dependency>
-
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-webartifactId>
- dependency>
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-actuatorartifactId>
- dependency>
-
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-devtoolsartifactId>
- <scope>runtimescope>
- <optional>trueoptional>
- dependency>
- <dependency>
- <groupId>cn.hutoolgroupId>
- <artifactId>hutool-allartifactId>
- <version>4.6.3version>
- dependency>
- <dependency>
- <groupId>org.projectlombokgroupId>
- <artifactId>lombokartifactId>
- <optional>trueoptional>
- dependency>
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-testartifactId>
- <scope>testscope>
- dependency>
-
- dependencies>
3.XML
- server:
- port: 8401
-
- spring:
- application:
- name: cloudalibaba-sentinel-service
- cloud:
- nacos:
- discovery:
- #Nacos服务注册中心地址
- server-addr: localhost:8848
- sentinel:
- transport:
- #配置Sentinel dashboard地址
- dashboard: localhost:8080
- #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
- port: 8719
-
- management:
- endpoints:
- web:
- exposure:
- include: '*'
4.主启动
- @EnableDiscoveryClient
- @SpringBootApplication
- public class MainApp8401
- {
- public static void main(String[] args) {
- SpringApplication.run(MainApp8401.class, args);
- }
- }
5.业务类
- @RestController
- public class FlowLimitController
- {
-
- @GetMapping("/testA")
- public String testA()
- {
- return "------testA";
- }
-
- @GetMapping("/testB")
- public String testB()
- {
- return "------testB";
- }
- }
6.测试
首先确保启动了Nacos和Sentinel服务。
连续输入: localhost:8401/testA localhost:8401/testB
Sentinel 后台的数据:(QPS-每秒的请求数)



RT(平均响应时间,秒级)
平均响应时间超出阈值且在时间窗口内通过的请求>=5,两个条件同时满足后触发降级
窗口期过后关闭断路器
RT最大4900(更大的需要通过-Dcsp.sentinel.statistic.max.rt=XXXX才能生效)

异常比列(秒级)
QPS >= 5 且异常比例(秒级统计)超过阈值时,触发降级;时间窗口结束后,关闭降级

异常数(分钟级)
异常数(分钟统计)超过阈值时,触发降级;时间窗口结束后,关闭降级


Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。
当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。
注:Sentinel的断路器是没有半开状态!
简单来说,@SentinelResource 用来标识资源名以及定义违反规则和代码出错时的兜底方法,类似于HystrixCommand 定义FallBack。系统默认有兜底方法,默认提示:Blocked by Sentinel (flow limiting)
还是在上面的 cloudalibaba-sentinel-service8401 中
1.POM引入自定义包
- <dependency>
- <groupId>com.atguigu.springcloudgroupId>
- <artifactId>cloud-api-commonsartifactId>
- <version>${project.version}version>
- dependency>
2.新建Controller
- @RestController
- public class RateLimitController
- {
- @GetMapping("/byResource")
- @SentinelResource(value = "byResource",blockHandler = "handleException")
- public CommonResult byResource()
- {
- return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001"));
- }
- public CommonResult handleException(BlockException exception)
- {
- return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服务不可用");
- }
- }
3.配置流控规则


4.测试
输入: localhost:8401/byResource 频次大于1时,会返回我们自定义的错误信息。
注:最好按照资源名设置流控规则,如果按照URL设置,只会使用默认的兜底方法。
上面方式的问题:
1 系统默认的,没有体现我们自己的业务要求。
2 依照现有条件,我们自定义的处理方法又和业务代码耦合在一块,不直观。
3 每个业务方法都添加一个兜底的,那代码膨胀加剧。
4 全局统一的处理方法没有体现。
1.自定义限流处理类- CustomerBlockHandler
- public class CustomerBlockHandler
- {
- public static CommonResult handleException(BlockException exception){
- return new CommonResult(2020,"自定义的限流处理信息......CustomerBlockHandler");
- }
- }
2.修改Controller
- @GetMapping("/rateLimit/customerBlockHandler")
- @SentinelResource(value = "customerBlockHandler",
- blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handleException")
- public CommonResult customerBlockHandler()
- {
- return new CommonResult(200,"按客户自定义限流处理逻辑");
- }
3.测试
设置流控规则

输入:
localhost:8401/rateLimit/customerBlockHandler 频次大于1时,会返回我们自定义的错误信息。
热点即经常访问的数据,很多时候我们希望统计或者限制某个热点数据中访问频次最高的TopN数据,并对其访问进行限流或者其它操作
1.修改Controller
- @GetMapping("/testHotKey")
- @SentinelResource(value = "testHotKey",blockHandler = "dealHandler_testHotKey")
- public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
- @RequestParam(value = "p2",required = false) String p2){
- return "------testHotKey";
- }
- public String dealHandler_testHotKey(String p1,String p2,BlockException exception)
- {
- return "-----dealHandler_testHotKey";
- }
2.设置热点规则

方法testHotKey里面第一个参数只要QPS超过每秒1次,马上降级处理
3.测试
输入: http://localhost:8401/testHotKey?p1=abc 频率超过1,报错
输入: http://localhost:8401/testHotKey?p1=abc&p2=33 频率超过1,报错
输入: http://localhost:8401/testHotKey?p2=abc 频率超过1,不报错
上面的示例中,参数p1当QPS超过1秒1次点击后马上被限流,假如我们期望p1参数是某个特殊值时,它的限流阈值和平时不一样。(就是在特定条件下允许例外),可以这样设置:

注:热点参数的注意点,参数必须是基本类型或者String


这个设置要慎重,因为全局的,影响到整个服务节点。不再演示
有两种方案:sentinel+ribbon / sentinel+openFeign
1.新建cloudalibaba-provider-payment9003/9004两个一样的做法,只是端口不同
2.POM
- <dependencies>
-
- <dependency>
- <groupId>com.alibaba.cloudgroupId>
- <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
- dependency>
- <dependency>
- <groupId>com.atguigu.springcloudgroupId>
- <artifactId>cloud-api-commonsartifactId>
- <version>${project.version}version>
- dependency>
-
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-webartifactId>
- dependency>
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-actuatorartifactId>
- dependency>
-
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-devtoolsartifactId>
- <scope>runtimescope>
- <optional>trueoptional>
- dependency>
- <dependency>
- <groupId>org.projectlombokgroupId>
- <artifactId>lombokartifactId>
- <optional>trueoptional>
- dependency>
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-testartifactId>
- <scope>testscope>
- dependency>
- dependencies>
3.YML
- server:
- port: 9003 #记得改
-
- spring:
- application:
- name: nacos-payment-provider
- cloud:
- nacos:
- discovery:
- server-addr: localhost:8848 #配置Nacos地址
-
- management:
- endpoints:
- web:
- exposure:
- include: '*'
4.主启动
- @SpringBootApplication
- @EnableDiscoveryClient
- public class PaymentMain9003
- {
- public static void main(String[] args) {
- SpringApplication.run(PaymentMain9003.class, args);
- }
- }
5.业务类
- @RestController
- public class PaymentController
- {
- @Value("${server.port}")
- private String serverPort;
-
- public static HashMap
hashMap = new HashMap<>(); - static
- {
- hashMap.put(1L,new Payment(1L,"28a8c1e3bc2742d8848569891fb42181"));
- hashMap.put(2L,new Payment(2L,"bba8c1e3bc2742d8848569891ac32182"));
- hashMap.put(3L,new Payment(3L,"6ua8c1e3bc2742d8848569891xt92183"));
- }
-
- @GetMapping(value = "/paymentSQL/{id}")
- public CommonResult
paymentSQL(@PathVariable("id") Long id) - {
- Payment payment = hashMap.get(id);
- CommonResult
result = new CommonResult(200,"from mysql,serverPort: "+serverPort,payment); - return result;
- }
-
- }
6.新建 cloudalibaba-consumer-nacos-order84
7.POM
-
- <dependencies>
-
- <dependency>
- <groupId>com.alibaba.cloudgroupId>
- <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
- dependency>
-
- <dependency>
- <groupId>com.alibaba.cloudgroupId>
- <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
- dependency>
-
- <dependency>
- <groupId>com.atguigu.springcloudgroupId>
- <artifactId>cloud-api-commonsartifactId>
- <version>${project.version}version>
- dependency>
-
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-webartifactId>
- dependency>
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-actuatorartifactId>
- dependency>
-
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-devtoolsartifactId>
- <scope>runtimescope>
- <optional>trueoptional>
- dependency>
- <dependency>
- <groupId>org.projectlombokgroupId>
- <artifactId>lombokartifactId>
- <optional>trueoptional>
- dependency>
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-testartifactId>
- <scope>testscope>
- dependency>
- dependencies>
8.YML
- server:
- port: 84
-
-
- spring:
- application:
- name: nacos-order-consumer
- cloud:
- nacos:
- discovery:
- server-addr: localhost:8848
- sentinel:
- transport:
- #配置Sentinel dashboard地址
- dashboard: localhost:8080
- #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
- port: 8719
-
-
- #消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者)
- service-url:
- nacos-user-service: http://nacos-payment-provider
9.主启动
- @EnableDiscoveryClient
- @SpringBootApplication
- public class OrderNacosMain84
- {
- public static void main(String[] args) {
- SpringApplication.run(OrderNacosMain84.class, args);
- }
- }
10.业务类
10.1 ApplicationContextConfig
- @Configuration
- public class ApplicationContextConfig
- {
- @Bean
- @LoadBalanced
- public RestTemplate getRestTemplate()
- {
- return new RestTemplate();
- }
- }
10.2 CircleBreakerController
@SentinelResource 设置fallback 、blockHandler 属性,可以分别处理运行时异常和违反sentinel规则的兜底方法

- @RestController
- @Slf4j
- public class CircleBreakerController
- {
- public static final String SERVICE_URL = "http://nacos-payment-provider";
-
- @Resource
- private RestTemplate restTemplate;
-
- @RequestMapping("/consumer/fallback/{id}")
- @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler")
- public CommonResult
fallback(@PathVariable Long id) - {
- CommonResult
result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id); - if (id == 4) {
- throw new IllegalArgumentException ("非法参数异常....");
- }else if (result.getData() == null) {
- throw new NullPointerException ("NullPointerException,该ID没有对应记录");
- }
- return result;
- }
- public CommonResult handlerFallback(@PathVariable Long id,Throwable e) {
- Payment payment = new Payment(id,"null");
- return new CommonResult<>(444,"fallback,无此流水,exception "+e.getMessage(),payment);
- }
- public CommonResult blockHandler(@PathVariable Long id,BlockException blockException) {
- Payment payment = new Payment(id,"null");
- return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException "+blockException.getMessage(),payment);
- }
-
- }
11.测试
在sentinel中进行配置:

首先输入: http://localhost:84/consumer/fallback/1 正常显示数据
连续输入上面的地址 blockHandler->
- {
- "code": 445,
- "message": "blockHandler-sentinel限流,无此流水: blockException null",
- "data": {
- "id": 1,
- "serial": "null"
- }
- }
再输入: http://localhost:84/consumer/fallback/4 fallback->
- {
- "code": 444,
- "message": "兜底异常handlerFallback,exception内容 IllegalArgumentException,非法参数异常....",
- "data": {
- "id": 4,
- "serial": "null"
- }
- }
注:若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。
1.消费端引入openfeign依赖
-
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-openfeignartifactId>
- dependency>
2.修改YML,激活sentinel对feigh的支持
- # 激活Sentinel对Feign的支持
- feign:
- sentinel:
- enabled: true
3.新建业务接口 PaymentService,带@FeignClient注解
- @FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)
- public interface PaymentService
- {
- @GetMapping(value = "/paymentSQL/{id}")
- public CommonResult
paymentSQL(@PathVariable("id") Long id); - }
4.新建异常处理业务类 PaymentFallbackService,实现 PaymentService
- @Component
- public class PaymentFallbackService implements PaymentService
- {
- @Override
- public CommonResult
paymentSQL(Long id) - {
- return new CommonResult<>(44444,"服务降级返回,---PaymentFallbackService",new Payment(id,"errorSerial"));
- }
- }
5.修改Controller
- @Resource
- private PaymentService paymentService;
-
- @GetMapping(value = "/consumer/paymentSQL/{id}")
- public CommonResult
paymentSQL(@PathVariable("id") Long id) - {
- return paymentService.paymentSQL(id);
- }
6.主启动类添加@EnableFeignClients注解
7.测试
输入: http://localhost:84/consumer/paymentSQL/1 正常显示
此时关闭8003、8004 返回fallback:
- {
- "code": 44444,
- "message": "服务降级返回,---PaymentFallbackService",
- "data": {
- "id": 4,
- "serial": "errorSerial"
- }
- }
一旦我们重启应用,sentinel规则将消失,生产环境需要将配置规则进行持久化,将限流配置规则持久化进Nacos保存。
比如我们希望对cloudalibaba-sentinel-service8401上的规则进行持久化:
1.POM
- <dependency>
- <groupId>com.alibaba.cspgroupId>
- <artifactId>sentinel-datasource-nacosartifactId>
- dependency>
2.YML
- spring:
- cloud:
- sentinel:
- datasource:
- ds1:
- nacos:
- server-addr: localhost:8848
- dataId: ${spring.application.name}
- groupId: DEFAULT_GROUP
- data-type: json
- rule-type: flow
3.Nacos中添加规则配置

- [
- {
- "resource": "/rateLimit/byUrl",
- "limitApp": "default",
- "grade": 1,
- "count": 1,
- "strategy": 0,
- "controlBehavior": 0,
- "clusterMode": false
- }
- ]
resource:资源名称;
limitApp:来源应用;
grade:阈值类型,0表示线程数,1表示QPS;
count:单机阈值;
strategy:流控模式,0表示直接,1表示关联,2表示链路;
controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;
clusterMode:是否集群。
4.测试
重启8041服务,发送如下请求:
http://localhost:8401/rateLimit/byUrl
刷新sentinel,可以看到持久化的配置规则了:
