Spring Cloud Alibaba Sentinel集成
Posted 我是廖志伟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Cloud Alibaba Sentinel集成相关的知识,希望对你有一定的参考价值。
主项目链接:https://gitee.com/java_wxid/java_wxid
项目架构及博文总结:
- 点击:【使用Spring Boot快速构建应用】
- 点击:【使用Spring Cloud Open Feign基于动态代理动态构造请求实现与其他系统进行交互】
- 点击:【使用Spring Cloud Hystrix实现服务容错、熔断、降级、监控】
- 点击:【使用Spring Cloud Ribbon以库的方式集成到服务的消费方实现客户端负载均衡】
- 点击:【使用Spring Cloud Gateway作为API网关服务进行请求拦截、服务分发、降级、限流】
- 点击:【使用Spring Cloud Security Oauth2作为微服务统一认证中心实现用户认证和授权访问】
- 点击:【使用Spring Cloud Stream作为消息驱动用于动态的切换中间件】
- 点击:【使用Spring Cloud Skywalking基于字节码注入通过探针方式进行链路追踪、分布式追踪、性能指标分析、应用和服务依赖分析】
- 点击:【使用Spring Cloud Alibaba Nacos实现服务注册/发现/续约/剔除/下线、心跳检测、服务配置管理、基于长轮训机制实现配置动态变更】
- 点击:【使用Spring Cloud Alibaba Seata作为对项目代码无入侵的分布式事务解决方案】
- 点击:【使用Spring Cloud Alibaba Sentinel实现高可用流量防护】
- 点击:【使用Apache ShardingSphere作为关系型数据库中间件实现分库分表、读写分离】
- 点击:【使用Apache Mybatis作为持久层框架用于定制化SQL、存储过程以及高级映射】
- 点击:【使用Redis作为高性能分布式缓存数据库】
- 点击:【使用ElasticSearch全文搜索】
- 点击:【使用MongoDB非关系型数据库】
- 点击:【使用xxl-job作为分布式任务调度平台】
- 点击:【使用Elasticsearch + Logstash + Kibana作为日志收集系统】
- 点击:【使用Apifox作为API文档、API调试、API Mock、API自动化测试】
- 点击:【使用Apache Spark作为基于内存计算的大数据分析引擎用于批处理、交互式查询】
- 点击:【使用ETL工具将数据源抽取到HDFS作为高可靠、高吞吐量的分布式文件系统存储,通过Hive清洗、处理和计算原始数据,Hive清洗处理后的结果,将存入Hbase,海量数据随机查询场景从HBase查询数据】
- 点击:【使用领域驱动DDD设计和设计模式进行开发】
- 点击:【使用Netty基于Java NIO封装的高性能的网络通信框架】
- 点击:【使用k8s、docker、docker-compose、宝塔面板进行环境搭建和部署】
- 点击:【使用Vue渐进式JavaScript框架作为适用场景丰富的Web前端框架】
- 点击:【分享人才筛选、工作分配、高效办公、项目推动等团队管理经验】
项目模块:
前期规划,实现部分
java_wxid
├── demo // 演示模块
│ └── 模块名称:apache-mybatis-demo模块 //Apache Mybatis集成(已实现并有博文总结)
│ └── 模块名称:apache-shardingsphere-demo模块 //Apache ShardingSphere集成(已实现并有博文总结)
│ └── 模块名称:design-demo模块 //设计模式实战落地(已实现并有博文总结)
│ └── 模块名称:elasticsearch-demo模块 //ElasticSearch集成(已实现并有博文总结)
│ └── 模块名称:mongodb-demo模块 //MongoDB集成(已实现并有博文总结)
│ └── 模块名称:redis-demo模块 //Redis集成(已实现并有博文总结)
│ └── 模块名称:spring-boot-demo模块 //Spring Boot快速构建应用(已实现并有博文总结)
│ └── 模块名称:spring-cloud-alibaba-nacos-demo模块 //Spring Cloud Alibaba Nacos集成(已实现并有博文总结)
│ └── 模块名称:spring-cloud-alibaba-seata-demo模块 //Spring Cloud Alibaba Seata集成(已实现并有博文总结)
│ └── 模块名称:spring-cloud-alibaba-sentinel-demo模块 //Spring Cloud Alibaba Sentinel集成(已实现并有博文总结)
│ └── 模块名称:spring-cloud-gateway-demo模块 //Spring Cloud Gateway集成(已实现并有博文总结)
│ └── 模块名称:spring-cloud-hystrix-demo模块 //Spring Cloud Hystrix集成(已实现并有博文总结)
│ └── 模块名称:spring-cloud-open-feign-demo模块 //Spring Cloud Open Feign集成(已实现并有博文总结)
│ └── 模块名称:spring-cloud-ribbon-demo模块 //Spring Cloud Ribbon集成(已实现并有博文总结)
│ └── 模块名称:spring-cloud-security-oauth2-demo模块 //Spring Cloud Security Oauth2集成(已实现并有博文总结)
│ └── 模块名称:spring-cloud-security-oauth2-sso-client-demo模块 //Spring Cloud Security Oauth2集成(已实现并有博文总结)
│ └── 模块名称:spring-cloud-skywalking-demo模块 //Spring Cloud Skywalking集成(已实现并有博文总结)
│ └── 模块名称:spring-cloud-stream-demo模块 //Spring Cloud Stream集成(已实现并有博文总结)
│ └── 模块名称:swagger-demo模块 //springfox-swagger2集成(已实现并有博文总结)
│ └── 模块名称:xxl-job模块 //xxl-job集成(已实现并有博文总结)
│ └── 模块名称:apache-spark-demo模块 //Apache Spark集成
│ └── 模块名称:etl-hdfs-hive-hbase-demo模块 //ETL、HDFS、Hive、Hbase集成
│ └── 模块名称:ddd-mode-demo模块 //DDD领域设计
│ └── 模块名称:netty-demo模块 //Netty集成
│ └── 模块名称:vue-demo模块 //前端vue集成
├── document // 文档
│ └── JavaKnowledgeDocument //java知识点
│ └── java基础知识点.md
│ └── mq知识点.md
│ └── mysql知识点.md
│ └── redis知识点.md
│ └── springcould知识点.md
│ └── spring知识点.md
│ └── FounderDocument //创始人
│ └── 创始人.md
系列文章:快速集成各种微服务相关的技术,帮助大家可以快速集成到自己的项目中,节约开发时间。
提示:系列文章还未全部完成,后续的文章,会慢慢补充进去的。
文章目录
- 创建spring-cloud-alibaba-sentinel-demo项目
- 修改pom.xml
- 修改SpringCloudAlibabaSentinelDemoApplication
- 创建bootstrap.yml
- 创建application.yml
- 创建SentinelConfig
- 创建HelloController
- 创建LimitFlowController
- 创建UserController
- 创建UserDao
- 创建AuthorityDemo
- 创建FlowThreadDemo
- 创建PaceFlowDemo
- 创建SystemGuardDemo
- 创建WarmUpFlowDemo
- 创建UserEntity
- 创建RRException
- 创建OrderFeignService
- 创建CommonBlockHandler
- 创建CommonFallback
- 创建MyBlockExceptionHandler
- 创建MyRequestOriginParser
- 创建MyUrlBlockHandler
- 创建UserServiceImpl
- 创建UserService
- 创建Constant
- 创建PageUtils
- 创建Query
- 创建R
- 创建HTMLFilter
- 创建SQLFilter
- 创建XssFilter
- 创建XssHttpServletRequestWrapper
- 创建UserDao.xml
创建spring-cloud-alibaba-sentinel-demo项目
项目代码:https://gitee.com/java_wxid/java_wxid/tree/master/demo/spring-cloud-alibaba-sentinel-demo
项目结构如下(示例):
修改pom.xml
代码如下(示例):
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spring-cloud-alibaba-sentinel-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-cloud-alibaba-sentinel-demo</name>
<description>Demo project for Spring Boot</description>
<!-- 属性配置-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!--引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。
在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系-->
<spring.boot.version>2.3.12.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR12</spring.cloud.version>
<spring.cloud.alibaba.version>2.2.7.RELEASE</spring.cloud.alibaba.version>
</properties>
<dependencies>
<!-- 代表web模块,在这个模块中含了许多JAR包,有spring相关的jar,内置tomcat服务器,jackson等,这些web项目中常用的的功能都会自动引入-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.4.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.4.1</version>
</dependency>
<!-- druid驱动-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.23</version>
</dependency>
<!-- mysql连接-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<!-- mybatis的一个库-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<!-- Alibaba Nacos 配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- 在SpringBoot 2.4.x的版本之后,对于bootstrap.properties/bootstrap.yaml配置文件(我们合起来成为Bootstrap配置文件)的支持,其实这个jar包里什么都没有,就只有一个标识类Marker,用来标识要开启Bootstrap配置文件的支持,由于父类用了2.5.6版本需要导入如下的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>3.1.0</version>
</dependency>
<!--openfeign客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<!--引入HttpClient依赖-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
<!-- 引入Feign Slf4j -->
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-slf4j</artifactId>
<version>8.14.4</version>
</dependency>
<!-- lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<!-- @SentinelResource 注解用来标识资源是否被限流、降级。
blockHandler: 定义当资源内部发生了BlockException应该进入的方法(捕获的是Sentinel定义的异常)
fallback: 定义的是资源内部发生了Throwable应该进入的方法
exceptionsToIgnore:配置fallback可以忽略的异常
源码入口:com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.8.0</version>
</dependency>
<!-- 流控规则设置可以通过Sentinel dashboard配置
客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信。-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.0</version>
</dependency>
<!--- 解决流控链路不生效的问题
从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>
<!-- Spring Cloud Alibaba整合Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--sentinel持久化 采用 Nacos 作为规则配置数据源-->
<!-- <dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>-->
</dependencies>
<!--
引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。
在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>$spring.boot.version</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>$spring.cloud.version</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>$spring.cloud.alibaba.version</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
修改SpringCloudAlibabaSentinelDemoApplication
代码如下(示例):
package com.example.springcloudalibabasentineldemo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@MapperScan("com.example.springcloudalibabasentineldemo.dao")
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class SpringCloudAlibabaSentinelDemoApplication
public static void main(String[] args)
SpringApplication.run(SpringCloudAlibabaSentinelDemoApplication.class, args);
创建bootstrap.yml
代码如下(示例):
#bootstrap.yml优先级比application.yml优先级高
spring:
#prefix−spring.profile.active.$file-extension
#nacos会根据当前环境去拼接配置名称查找相应配置文件,
#示例:spring.application.name-spring.profiles.active-spring.cloud.nacos.config.file-extension
#获取到值:nacos-autoconfig-service-dev.yml
profiles:
#开发环境dev,测试环境test,生产环境prod
active: dev
application:
#配置应用的名称,用于获取配置
name: spring-cloud-alibaba-sentinel-demo
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: 106.14.132.94:8848
config:
#nacos配置中心地址
server-addr: 106.14.132.94:8848
#配置中心的命名空间id
namespace: 9e50b6d9-6c3d-4e7a-b701-10f085e4b98d
#配置分组,默认没有也可以
group: DEFAULT_GROUP
#配置文件后缀,用于拼接配置配置文件名称,目前只支持yaml和properties
file-extension: yaml
#配置自动刷新
refresh-enabled: true
#配置文件的前缀,默认是application.name的值,如果配了prefix,就取prefix的值
#prefix: nacos-autoconfig-service-$spring.profile.active
# 配置编码
encode: UTF-8
username: nacos
password: nacos
创建application.yml
代码如下(示例):
server:
port: 8095
#暴露actuator端点 http://localhost:8800/actuator/sentinel
management:
endpoints:
web:
exposure:
include: '*'
spring:
application:
name: mall-user-sentinel-demo
cloud:
sentinel:
transport:
# 添加sentinel的控制台地址
dashboard: 127.0.0.1:8080
# 指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer
#port: 8719
# datasource:
# ds1:
# nacos:
# server-addr: 127.0.0.1:8848
# dataId: $spring.application.name
# groupId: DEFAULT_GROUP
# data-type: json
# rule-type: flow
#数据库配置
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://139.224.137.74:3306/syncdemo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: ca0a997ee4770063
#mybatis
mybatis-plus:
mapper-locations: classpath*:/mapper/*.xml
#实体扫描,多个package用逗号或者分号分隔
typeAliasesPackage: com.example.springcloudalibabasentineldemo.entity
创建SentinelConfig
代码如下(示例):
package com.example.springcloudalibabasentineldemo.config;
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
import com.example.springcloudalibabasentineldemo.sentinel.MyUrlBlockHandler;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @className: SentinelConfig
* @description: https://github.com/alibaba/Sentinel/issues/1213
* @author: zhiweiLiao
* @date: 2022-09-13 15:28
*/
@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);
//CommonFilter的BlockException自定义处理逻辑
WebCallbackManager.setUrlBlockHandler(new MyUrlBlockHandler());
//解决授权规则不生效的问题
//com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser
//WebCallbackManager.setRequestOriginParser(new MyRequestOriginParser());
return registration;
创建HelloController
代码如下(示例):
package com.example.springcloudalibabasentineldemo.controller;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
/**
* @description:
* @author: zhiweiLiao
* @date: 2022-09-13 15:28
*/
@RestController
@Slf4j
public class HelloController
private static final String RESOURCE_NAME = "hello";
@RequestMapping(value = "/hello")
public String hello()
Entry entry = null;
try
// 资源名可使用任意有业务语义的字符串,比如方法名、接口名或其它可唯一标识的字符串。
entry = SphU.entry(RESOURCE_NAME);
// 被保护的业务逻辑
String str = "hello world";
log.info("====="+str+"=====");
return str;
catch (BlockException e1)
// 资源访问阻止,被限流或被降级
//进行相应的处理操作
log.info("block!");
return "被流控了!";
catch (Exception ex)
// 若需要配置降级规则,需要通过这种方式记录业务异常
Tracer.traceEntry(ex, entry);
finally
if (entry != null)
entry.exit();
return null;
/**
* 定义流控规则
*/
@PostConstruct
private static void initFlowRules()
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
//设置受保护的资源
rule.setResource(RESOURCE_NAME);
// 设置流控规则 QPS
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 设置受保护的资源阈值
// Set limit QPS to 20.
rule.setCount(1);
rules.add(rule);
// 加载配置好的规则
FlowRuleManager.loadRules(rules);
创建LimitFlowController
代码如下(示例):
package com.example.springcloudalibabasentineldemo.controller;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.springcloudalibabasentineldemo.entity.UserEntity;
import com.example.springcloudalibabasentineldemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @description:
* @author: zhiweiLiao
* @date: 2022-09-13 15:28
*/
@RestController
public class LimitFlowController
@RequestMapping("/test")
// @SentinelResource(value = "test",blockHandlerClass = CommonBlockHandler.class,blockHandler = "handleException3")
public String test()
try
Thread.sleep(100);
catch (InterruptedException e)
e.printStackTrace();
return "========test()========";
AtomicInteger atomicInteger = new AtomicInteger();
@RequestMapping("/test2")
public String test2()
atomicInteger.getAndIncrement();
if (atomicInteger.get() % 2 == 0)
//模拟异常和异常比率
int i = 1/0;
return "========test2()========";
@Autowired
private UserService userService;
@RequestMapping(value = "/test3") //CommonFilter
public UserEntity test3()
UserEntity user = userService.getUser(1);
return user;
@RequestMapping(value = "/test4")
public UserEntity test4()
UserEntity user = userService.getUser(1);
return user;
public String handleException(BlockException exception)
return "===被限流降级啦===";
创建UserController
代码如下(示例):
package com.example.springcloudalibabasentineldemo.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.springcloudalibabasentineldemo.entity.UserEntity;
import com.example.springcloudalibabasentineldemo.feign.OrderFeignService;
import com.example.springcloudalibabasentineldemo.sentinel.CommonBlockHandler;
import com.example.springcloudalibabasentineldemo.sentinel.CommonFallback;
import com.example.springcloudalibabasentineldemo.service.UserService;
import com.example.springcloudalibabasentineldemo.utils.PageUtils;
import com.example.springcloudalibabasentineldemo.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.Map;
/**
* @description:
* @author: zhiweiLiao
* @date: 2022-09-13 15:28
*/
@RestController
@RequestMapping(value = "/user")
public class UserController
@Autowired
private UserService userService;
@Autowired
OrderFeignService orderFeignService;
@RequestMapping(value = "/getNacosConfigure")
@SentinelResource(value = "getNacosConfigure",
blockHandlerClass = CommonBlockHandler.class,
blockHandler = "getNacosConfigure",
fallbackClass = CommonFallback.class,
fallback = "getNacosConfigure"
)
public String getNacosConfigure()
// try
// // 模拟测试并发线程数限流
// Thread.sleep(900);
// catch (InterruptedException e)
// e.printStackTrace();
//
// findOrderByUserId 限流规则 2 sentinel dashboard 定义规则
//feign调用
String result = orderFeignService.getNacosConfigure();
return result;
/**
* 列表
*/
@RequestMapping("/list")
@SentinelResource(value = "userlist",
blockHandlerClass = CommonBlockHandler.class,
blockHandler = "handleException",fallback = "fallback")
public R list(@RequestParam Map<String, Object> params)
PageUtils page = userService.queryPage(params);
// int i=1/0;
return R.ok().put("page", page);
public R handleException(@RequestParam Map<String, Object> params,BlockException exception)
return R.error(-1,"===被限流降级啦===");
/**
* 信息
*/
@RequestMapping("/info/id")
@SentinelResource(value = "userinfo",
blockHandlerClass = CommonBlockHandler.class,
blockHandler = "handleException2",
fallbackClass = CommonFallback.class,
fallback = "fallback"
)
public R info(@PathVariable("id") Integer id)
UserEntity user = userService.getById(id);
if(id==4)
throw new IllegalArgumentException("异常参数");
return R.ok().put("mapper", user);
public R handleException2(@PathVariable("id") Integer id, BlockException exception)
return R.error(-1,"===被限流降级啦===");
public R fallback(@PathVariable("id") Integer id,Throwable e)
return R.error(-1,"===被熔断降级啦==="+e.getMessage());
/**
* 保存
*/
@RequestMapping("/save")
public R save(@RequestBody UserEntity user)
userService.save(user);
return R.ok();
/**
* 修改
*/
@RequestMapping("/update")
public R update(@RequestBody UserEntity user)
userService.updateById(user);
return R.ok();
/**
* 删除
*/
@RequestMapping("/delete")
public R delete(@RequestBody Integer[] ids)
userService.removeByIds(Arrays.asList(ids));
return R.ok();
创建UserDao
代码如下(示例):
package com.example.springcloudalibabasentineldemo.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.springcloudalibabasentineldemo.entity.UserEntity;
import org.apache.ibatis.annotations.Mapper;
/**
* @description:
* @author: zhiweiLiao
* @date: 2022-09-13 15:28
*/
@Mapper
public interface UserDao extends BaseMapper<UserEntity>
创建AuthorityDemo
代码如下(示例):
package com.example.springcloudalibabasentineldemo.demo;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import java.util.Collections;
/**
* @description:
* @author: zhiweiLiao
* @date: 2022-09-13 15:28
*/
public class AuthorityDemo
private static final String RESOURCE_NAME = "testABC";
public static void main(String[] args)
System.out.println("========Testing for black list========");
initBlackRules();
testFor(RESOURCE_NAME, "appA");
testFor(RESOURCE_NAME, "appB");
testFor(RESOURCE_NAME, "appC");
testFor(RESOURCE_NAME, "appE");
System.out.println("========Testing for white list========");
initWhiteRules();
testFor(RESOURCE_NAME, "appA");
testFor(RESOURCE_NAME, "appB");
testFor(RESOURCE_NAME, "appC");
testFor(RESOURCE_NAME, "appE");
private static void testFor(/*@NonNull*/ String resource, /*@NonNull*/ String origin)
ContextUtil.enter(resource, origin);
Entry entry = null;
try
entry = SphU.entry(resource);
System.out.println(String.format("Passed for resource %s, origin is %s", resource, origin));
catch (BlockException ex)
System.err.println(String.format("Blocked for resource %s, origin is %s", resource, origin));
finally
if (entry != null)
entry.exit();
ContextUtil.exit();
private static void initWhiteRules()
AuthorityRule rule = new AuthorityRule();
rule.setResource(RESOURCE_NAME);
rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
rule.setLimitApp("appA,appE");
AuthorityRuleManager.loadRules(Collections.singletonList(rule));
private static void initBlackRules()
AuthorityRule rule = new AuthorityRule();
rule.setResource(RESOURCE_NAME);
rule.setStrategy(RuleConstant.AUTHORITY_BLACK);
rule.setLimitApp("appA,appB");
AuthorityRuleManager.loadRules(Collections.singletonList(rule));
创建FlowThreadDemo
代码如下(示例):
package com.example.springcloudalibabasentineldemo.demo;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.util.TimeUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @description:
* @author: zhiweiLiao
* @date: 2022-09-13 15:28
*/
public class FlowThreadDemo
private static AtomicInteger pass = new AtomicInteger();
private static AtomicInteger block = new AtomicInteger();
private static AtomicInteger total = new AtomicInteger();
private static AtomicInteger activeThread = new AtomicInteger();
private static volatile boolean stop = false;
private static final int threadCount = 100;
private static int seconds = 60 + 40;
private static volatile int methodBRunningTime = 2000;
public static void main(String[] args) throws Exception
System.out.println(
"MethodA will call methodB. After running for a while, methodB becomes fast, "
+ "which make methodA also become fast ");
tick();
initFlowRule();
for (int i = 0; i < threadCount; i++)
Thread entryThread = new Thread(new Runnable()
@Override
public void run()
while (true)
Entry methodA = null;
try
TimeUnit.MILLISECONDS.sleep(5);
methodA = SphU.entry("methodA");
activeThread.incrementAndGet();
Entry methodB = SphU.entry("methodB");
TimeUnit.MILLISECONDS.sleep(methodBRunningTime);
methodB.exit();
pass.addAndGet(1);
catch (BlockException e1)
block.incrementAndGet();
catch (Exception e2)
// biz exception
finally
total.incrementAndGet();
if (methodA != null)
methodA.exit();
activeThread.decrementAndGet();
);
entryThread.setName("working thread");
entryThread.start();
private static void initFlowRule()
List<FlowRule> rules = new ArrayList<FlowRule>();
FlowRule rule1 = new FlowRule();
rule1.setResource("methodA");
// set limit concurrent thread for 'methodA' to 20
rule1.setCount(20);
rule1.setGrade(RuleConstant.FLOW_GRADE_THREAD);
rule1.setLimitApp("default");
rules.add(rule1);
FlowRuleManager.loadRules(rules);
private static void tick()
Thread timer = new Thread(new TimerTask());
timer.setName("sentinel-timer-task");
timer.start();
static class TimerTask implements Runnable
@Override
public void run()
long start = System.currentTimeMillis();
System.out.println("begin to statistic!!!");
long oldTotal = 0;
long oldPass = 0;
long oldBlock = 0;
while (!stop)
try
TimeUnit.SECONDS.sleep(1);
catch (InterruptedException e)
long globalTotal = total.get();
long oneSecondTotal = globalTotal - oldTotal;
oldTotal = globalTotal;
long globalPass = pass.get();
long oneSecondPass = globalPass - oldPass;
oldPass = globalPass;
long globalBlock = block.get();
long oneSecondBlock = globalBlock - oldBlock;
oldBlock = globalBlock;
System.out.println(seconds + " total qps is: " + oneSecondTotal);
System.out.println(TimeUtil.currentTimeMillis() + ", total:" + oneSecondTotal
+ ", pass:" + oneSecondPass
+ ", block:" + oneSecondBlock
+ " activeThread:" + activeThread.get());
if (seconds-- <= 0)
stop = true;
if (seconds == 40)
System.out.println("method B is running much faster; more requests are allowed to pass");
methodBRunningTime = 20;
long cost = System.currentTimeMillis() - start;
System.out.println("time cost: " + cost + " ms");
System.out.println("total:" + total.get() + ", pass:" + pass.get()
+ ", block:" + block.get());
System.exit(0);
创建PaceFlowDemo
代码如下(示例):
package com.example.springcloudalibabasentineldemo.demo;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.util.TimeUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @description:
* @author: zhiweiLiao
* @date: 2022-09-13 15:28
*/
public class PaceFlowDemo
private static final String KEY = "abc";
private static volatile CountDownLatch countDown;
private static final Integer requestQps = 100;
private static final Integer count = 10;
private static final AtomicInteger done = new AtomicInteger();
private static final AtomicInteger pass = new AtomicInteger();
private static final AtomicInteger block = new AtomicInteger();
public static void main(String[] args) throws InterruptedException
System.out.println("pace behavior");
countDown = new CountDownLatch(1);
initPaceFlowRule();
simulatePulseFlow();
countDown.await();
System.out.println("done");
System.out.println("total pass:" + pass.get() + ", total block:" + block.get());
System.out.println();
System.out.println("default behavior");
TimeUnit.SECONDS.sleep(5);
done.set(0);
pass.set(0);
block.set(0);
countDown = new CountDownLatch(1);
initDefaultFlowRule();
simulatePulseFlow();
countDown.await();
System.out.println("done");
System.out.println("total pass:" + pass.get() + ", total block:" + block.get());
System.exit(0);
private static void initPaceFlowRule()
List<FlowRule> rules = new ArrayList<FlowRule>();
FlowRule rule1 = new FlowRule();
rule1.setResource(KEY);
rule1.setCount(count);
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule1.setLimitApp("default");
/*
* CONTROL_BEHAVIOR_RATE_LIMITER means requests more than threshold will be queueing in the queue,
* until the queueing time is more than @link FlowRule#maxQueueingTimeMs, the requests will be rejected.
*/
rule1.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
rule1.setMaxQueueingTimeMs(20 * 1000);
rules.add(rule1);
FlowRuleManager.loadRules(rules);
private static void initDefaultFlowRule()
List<FlowRule> rules = new ArrayList<FlowRule>();
FlowRule rule1 = new FlowRule();
rule1.setResource(KEY);
rule1.setCount(count);
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule1.setLimitApp("default");
// CONTROL_BEHAVIOR_DEFAULT means requests more than threshold will be rejected immediately.
rule1.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
rules.add(rule1);
FlowRuleManager.loadRules(rules);
private static void simulatePulseFlow()
for (int i = 0; i < requestQps; i++)
Thread thread = new Thread(new Runnable()
@Override
public void run()
long startTime = TimeUtil.currentTimeMillis();
Entry entry = null;
try
entry = SphU.entry(KEY);
catch (BlockException e1)
block.incrementAndGet();
catch (Exception e2)
// biz exception
finally
if (entry != null)
entry.exit();
pass.incrementAndGet();
long cost = TimeUtil.currentTimeMillis() - startTime;
System.out.println(
TimeUtil.currentTimeMillis() + " one request pass, cost " + cost + " ms");
try
TimeUnit.MILLISECONDS.sleep(5);
catch (InterruptedException e1)
// ignore
if (done.incrementAndGet() >= requestQps)
countDown.countDown();
, "Thread " + i);
thread.start();
创建SystemGuardDemo
代码如下(示例):
package com.example.springcloudalibabasentineldemo.demo;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.alibaba.csp.sentinel.util.TimeUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @description:
* @author: zhiweiLiao
* @date: 2022-09-13 15:28
*/
public class SystemGuardDemo
private static AtomicInteger pass = new AtomicInteger();
private static AtomicInteger block = new AtomicInteger();
private static AtomicInteger total = new AtomicInteger();
private static volatile boolean stop = false;
private static final int threadCount = 100;
private static int seconds = 60 + 40;
public static void main(String[] args) throws Exception
tick();
initSystemRule();
for (int i = 0; i < threadCount; i++)
Thread entryThread = new Thread(new Runnable()
@Override
public void run()
while (true)
Entry entry = null;
try
entry = SphU.entry("methodA", EntryType.IN);
pass.incrementAndGet();
try
TimeUnit.MILLISECONDS.sleep(20);
catch (InterruptedException e)
// ignore
catch (BlockException e1)
block.incrementAndGet();
try
TimeUnit.MILLISECONDS.sleep(20);
catch (InterruptedException e)
// ignore
catch (Exception e2)
// biz exception
finally
total.incrementAndGet();
if (entry != null)
entry.exit();
);
entryThread.setName("working-thread");
entryThread.start();
private static void initSystemRule()
List<SystemRule> rules = new ArrayList<SystemRule>();
SystemRule rule = new SystemRule();
// max load is 3
rule.setHighestSystemLoad(3.0);
// max cpu usage is 60%
rule.setHighestCpuUsage(0.6);
// max avg rt of all request is 10 ms
rule.setAvgRt(10);
// max total qps is 20
rule.setQps(20);
// max parallel working thread is 10
rule.setMaxThread(10);
rules.add(rule);
SystemRuleManager.loadRules(Collections.singletonList(rule));
private static void tick()
Thread timer = new Thread(new TimerTask());
timer.setName("sentinel-timer-task");
timer.start();
static class TimerTask implements Runnable
@Override
public void run()
System.out.println("begin to statistic!!!");
long oldTotal = 0;
long oldPass = 0;
long oldBlock = 0;
while (!stop)
try
TimeUnit.SECONDS.sleep(1);
catch (InterruptedException e)
long globalTotal = total.get();
long oneSecondTotal = globalTotal - oldTotal;
oldTotal = globalTotal;
long globalPass = pass.get();
long oneSecondPass = globalPass - oldPass;
oldPass = globalPass;
long globalBlock = block.get();
long oneSecondBlock = globalBlock - oldBlock;
oldBlock = globalBlock;
System.out.println(seconds + ", " + TimeUtil.currentTimeMillis() + ", total:"
+ oneSecondTotal + ", pass:"
+ oneSecondPass + ", block:" + oneSecondBlock);
if (seconds-- <= 0)
stop = true;
System.exit(0);
创建WarmUpFlowDemo
代码如下(示例):
package com.example.springcloudalibabasentineldemo.demo;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.util.TimeUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @description:
* @author: zhiweiLiao
* @date: 2022-09-13 15:28
*/
public class WarmUpFlowDemo
private static final String KEY = "abc";
private static AtomicInteger pass = new AtomicInteger();
private static AtomicInteger block = new AtomicInteger();
private static AtomicInteger total = new AtomicInteger();
private static volatile boolean stop = false;
private static final int threadCount = 100;
private static int seconds = 60 + 40;
public static void main(String[] args) throws Exception
initFlowRule();
// trigger Sentinel internal init
Entry entry = null;
try
entry = SphU.entry(KEY);
catch (Exception e)
finally
if (entry != null)
entry.exit();
Thread timer = new Thread(new TimerTask());
timer.setName("sentinel-timer-task");
timer.start();
//first make the system run on a very low condition
for (int i = 0; i < 3; i++)
Thread t = new Thread(new WarmUpTask());
t.setName("sentinel-warmup-task");
t.start();
Thread.sleep(20000);
/*
* Start more thread to simulate more qps. Since we use @link RuleConstant.CONTROL_BEHAVIOR_WARM_UP as
* @link FlowRule#controlBehavior, real passed qps will increase to @link FlowRule#count in
* @link FlowRule#warmUpPeriodSec seconds.
*/
for (int i = 0; i < threadCount; i++)
Thread t = new Thread(new RunTask());
t.setName("sentinel-run-task");
t.start();
private static void initFlowRule()
List<FlowRule> rules = new ArrayList<FlowRule>();
FlowRule rule1 = new FlowRule();
rule1.setResource(KEY);
rule1.setCount(20);
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule1.setLimitApp("default");
rule1.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
rule1.setWarmUpPeriodSec(10);
rules.add(rule1);
FlowRuleManager.loadRules(rules);
static class WarmUpTask implements Runnable
@Override
public void run()
while (!stop)
Entry entry = null;
try
entry = SphU.entry(KEY);
// token acquired, means pass
pass.addAndGet(1);
catch (BlockException e1)
block.incrementAndGet();
catch (Exception e2)
// biz exception
finally
total.incrementAndGet();
if (entry != null)
entry.exit();
Random random2 = new Random();
try
TimeUnit.MILLISECONDS.sleep(random2.nextInt(2000));
catch (InterruptedException e)
// ignore
static class RunTask implements Runnable
@Override
public void run()
while (!stop)
Entry entry = null;
try
entry = SphU.entry(KEY);
pass.addAndGet(1);
catch (BlockException e1)
block.incrementAndGet();
catch (Exception e2)
// biz exception
finally
total.incrementAndGet();
if (entry != null)
entry.exit();
Random random2 = new Random();
try
TimeUnit.MILLISECONDS.sleep(random2.nextInt(50));
catch (InterruptedException e)
// ignore
static class TimerTask implements Runnable
@Override
public void run()
long start = System.currentTimeMillis();
System.out.println("begin to statistic!!!");
long oldTotal = 0;
long oldPass = 0;
long oldBlock = 0;
while (!stop)
try
TimeUnit.SECONDS.sleep(1);
catch (InterruptedException e)
long globalTotal = total.get();
long oneSecondTotal = globalTotal - oldTotal;
oldTotal = globalTotal;
long globalPass = pass.get();
long oneSecondPass = globalPass - oldPass;
oldPass = globalPass;
long globalBlock = block.get();
long oneSecondBlock = globalBlock - oldBlock;
oldBlock = globalBlock;
System.out.println(TimeUtil.currentTimeMillis() + ", total:" + oneSecondTotal
+ ", pass:" + oneSecondPass
+ ", block:" + oneSecondBlock);
if (seconds-- <= 0)
stop = true;
long cost = System.currentTimeMillis() - start;
System.out.println("time cost: " + cost + " ms");
System.out.println("total:" + total.get() + ", pass:" + pass.get()
+ ", block:" + block.get());
System.exit(0);
创建UserEntity
代码如下(示例):
package com.example.springcloudalibabasentineldemo.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
/**
* @className: RedisController
* @description:
* @author: zhiweiLiao
* @date: 2022-09-13 15:28
*/
@Data
@TableName("t_user")
public class UserEntity implements Serializable
private static final long serialVersionUID = 1L;
/**
*
*/
@TableId
private Integer id;
/**
*
*/
private String username;
/**
*
*/
private Integer age;
创建RRException
代码如下(示例):
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.example.springcloudalibabasentineldemo.exception;
/**
* @description:自定义异常
* @author: zhiweiLiao
* @date: 2022-09-13 15:28
*/
public class RRException extends RuntimeException
private static final long serialVersionUID = 1L;
private String msg;
private int code = 500;
public RRException(String msg)
super(msg);
this.msg = msg;
public RRException(String msg, Throwable e)
super(msg, e);
this.msg = msg;
public RRException(String msg, int code)
super(msg);
this.msg = msg;
this.code = code;
public RRException(String msg, int code, Throwable e)
super(msg, e);
this.msg = msg;
this.code = code;
public String getMsg()
return msg;
public void setMsg(String msg)
this.msg = msg;
以上是关于Spring Cloud Alibaba Sentinel集成的主要内容,如果未能解决你的问题,请参考以下文章
Spring Cloud Alibaba全家桶——Spring Cloud Alibaba介绍
Spring Cloud Alibaba系列教程——Spring Cloud Alibaba开篇
spring boot 整合spring cloud alibaba