Spring Cloud Alibaba-Sentinel服务熔断组件学习
前言
Spring Cloud Alibaba-Sentinel服务熔断组件学习
提示:以下是本篇文章正文内容,下面案例可供参考
一、Sentinel的介绍
Sentinel是阿里中间件团队开源的,面向分布式服务架构的轻量级高可用流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来帮助用户保护服务的稳定性。
1.1 限流的作用
保护系统避免被瞬时流量冲垮
预防恶意请求
针对请求进行限制
服务器
应用(接口的处理能力(QPS/TPS))。RT ->Jmeter(压测)
资源限制(cpu(线程池)、内存()、网络资源)
如何控制流量
限流的指标(可以容纳的流量、已经容纳的流量、可以接受的流量)阈值
限流的过程(通过算法来实现)
限流的结果(处理策略)
1.2 限流的算法
计数器(Zk: RequestThrottle),线程池大小,连接数大小。
滑动窗口(TCP协议会自动改变滑动窗口的大小,
漏桶(控制传输速率)
水的流出速度是固定的
桶的大小也是固定的
令牌桶算法
1.3 限流的实现
Guava
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>22.0</version>
</dependency>
public class RateLimiterDemo {
//令牌桶算法
RateLimiter rateLimiter=RateLimiter.create(10); //TPS=10
public void doRequest(){
if(rateLimiter.tryAcquire()){ //获取令牌
System.out.println("success");
}else{
System.out.println("failed");
}
}
public static void main(String[] args) {
}
}
Semphore
分布式限流
1.4 Sentinel(看官方文档)
1、Sentinel流程图
2、Sentinel的定义
Sentinel是阿里中间件团队开源的,面向分布式服务架构的轻量级高可用流量控制组件,主要以流量为切入点,从流量控制,熔断降级,系统负载保护等多个维度来帮助用户保护服务的稳定性
3、Sentinel的技术图
二、Sentinel的使用
2.1 建立项目并且选择Spring Cloud Alibaba Sentinel
2.2 导入依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.0</version>
</dependency>
2.3 创建sentinelDemo并且进行编写
public class SentinelDemo {
public static void main(String[] args) {
while (true){
initFlowRule(); //初始化限流规则
//ResourceName表示资源,控制访问流量的点
try (Entry entry= SphU.entry("helloWorld")){
System.out.println("hello world");
} catch (BlockException e) {
System.out.println("被拒绝");
}
}
}
//限流规则
private static void initFlowRule(){
List<FlowRule> rules=new ArrayList<>();
FlowRule flowRule=new FlowRule();
//如果这里写helloWorld会显示被拒绝(限流)但是不写入helloworld则不会
flowRule.setResource("helloWorld123"); //针对那个资源设置规则
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS); //QPS或者并发数
rules.add(flowRule);
FlowRuleManager.loadRules(rules);
}
}
2.4 查询结果
flowRule.setResource(“helloWorld123”); 因为不是针对helloWorld,所以请求成功
flowRule.setResource(“helloWorld”); 因为针对了helloWorld,导致限流,所以请求被拒绝
2.5 服务熔断
通过并发线程数进行限制
针对响应时间
创建TestService服务
@Service
public class TestService {
@SentinelResource(value = "doTest",blockHandler ="blockHandler",fallback = "fallback") //声明限流的资源
public String doTest(String name){
return "hello , "+name;
}
public String blockHandler(String name, BlockException e){ //降级,限流触发的
return "被限流了";
}
public String fallback(String name){ //熔断触发的
return "被降级了";
}
}
创建SentinelController
@RestController
public class SentinelController {
@Autowired
TestService testService;
@GetMapping("/hello/{name}")
public String sayHello(@PathVariable("name") String name){
return testService.doTest(name);
}
}
在Springboot启动类中添加initFlowRule
@SpringBootApplication
public class SpringbootSentinelApplication {
public static void main(String[] args) {
initFlowRule();
SpringApplication.run(SpringbootSentinelApplication.class, args);
}
private static void initFlowRule() {
List<FlowRule> rules = new ArrayList<>();
FlowRule flowRule = new FlowRule();
flowRule.setResource("doTest"); //针对那个资源设置规则
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);//QPS或者并发数
flowRule.setCount(5); //QPS=5
rules.add(flowRule);
FlowRuleManager.loadRules(rules);
}
}
进入页面显示,访问成功
快速刷新页面,会发现被限流,会进入限流处理的事务(如果不写限流处理事务则会报500错误)
详解:如果有blockHandler 触发blockHandler ,有fallback 触发fallback 两者都有触发blockHandler
三、Sentinel中的流量控制
正常,则通过
被限制,抛出FlowException(FlowException extends BlockException)
同一个资源创建不同的规则,List
一个规则有什么组成
1、resource资源
2、count阈值
3、grade
4、limitApp 针对的调用来源
5、strategy,调用关系限流
6、controllBehavior(直接拒绝,冷启动,匀速排队)
流量控制的两种方法
并发线程数量
QPS
资源
规则
Entry->请求
限流规则的核心因素
resource
count
grade
limitApp
并发线程数
Hystrix 线程池隔离
Sentinel 并发线程数
QPS(TPS)
策略(流量控制的策略
直接拒绝
warmup
Dubbo,负载均衡策略时候
匀速排队
通过ControllerBehavior属性来控制策略
基于调用关系来做流量控制(纬度)
Flowule
limitApp
根据调用方来限流
根据调用链路入口来限流
针对具有关系的资源来限流
四、Sentinel控制台
1、下载sentinel-dashboard-1.8.4.jar
2、通过指令启动Sentinel控制台
java -Dserver.port=8777 -Dcsp.sentinel.dashboard.server=localhost:8777 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.4.jar
3、配置文件挂载到控制台上
导入依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
</dependency>
# Sentinel 控制台地址
spring.cloud.sentinel.transport.dashboard=localhost:8777
4、登录Sentinel
账号密码默认为sentinel
挂载成功显示
5、Jmeter进行压测
打开Jmeter新建一个Http请求
配置线程池
配置http请求
运行测试,观察控制台可以看见波动
五、动态限流规则
config center: zookeeper / apollo / etcd / redis / Consul / Eureka / Nacos
规则的感知(Pull,Push)
DataSource(接口)
pull
push
Sentinel扩展(InitFunc实现)
原来代码是放在主方法里面的
@SpringBootApplication
public class SpringBootSentinelApplication {
public static void main(String[] args) {
initFlowRule();
SpringApplication.run(SpringBootSentinelApplication.class, args);
}
/**
*定义限流规则,初始化规则方便使用
*/
private static void initFlowRule(){
List<FlowRule> rules = new ArrayList<>();
FlowRule flowRule = new FlowRule();
//绑定规则名称,针对那个规则设置规则
flowRule.setResource("doTest");
//QPS或者并发数
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
//QPS=5
flowRule.setCount(5);
//添加规则
rules.add(flowRule);
FlowRuleManager.loadRules(rules);
}
}
现在创建FlowRuleInitFunc 引用InitFunc接口
public class FlowRuleInitFunc implements InitFunc {
@Override
/**
*定义限流规则,初始化规则方便使用
*/
public void init() throws Exception {
List<FlowRule> rules = new ArrayList<>();
FlowRule flowRule = new FlowRule();
//绑定规则名称,针对那个规则设置规则
flowRule.setResource("doTest");
//QPS或者并发数
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
//QPS=5
flowRule.setCount(5);
//添加规则
rules.add(flowRule);
FlowRuleManager.loadRules(rules);
}
}
接着将对应的类名添加到位于资源目录(通常是 resource 目录)下的 META-INF/services 目录下的 com.alibaba.csp.sentinel.init.InitFunc 文件中,比如我们将上述的 com.test.init.DataSourceInitFunc 添加到文件中。当初次访问任意资源的时候,Sentinel 就可以自动去注册对应的数据源了。
com.gupaoedu.example.springbootsentinel.FlowRuleInitFunc
这样可以不用在启动类下面去写规则
六、使用Nacos设置限流规则
1. 导入依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.8.0</version>
</dependency>
2.编写方法
public class FlowRuleInitFunc implements InitFunc {
private final String nacosAddress = "127.0.0.1:8848";
private final String groupId = "SENTINEL_GROUP";
private final String dataId ="SpringBoot-sentinel";
@Override
/**
*定义限流规则,初始化规则方便使用
*/
public void init() throws Exception {
List<FlowRule> rules = new ArrayList<>();
// FlowRule flowRule = new FlowRule();
// //绑定规则名称,针对那个规则设置规则
// flowRule.setResource("resource_Name");
// //QPS或者并发数
// flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// //QPS=5
// flowRule.setCount(5);
// //添加规则
// rules.add(flowRule);
// FlowRuleManager.loadRules(rules);
//从远程服务器加载规则(Nacos)
ReadableDataSource<String,List<FlowRule>> flowRuleDs =
new NacosDataSource<List<FlowRule>>(nacosAddress,groupId,dataId,
s -> JSON.parseObject(s,new TypeReference<List<FlowRule>>(){}));
FlowRuleManager.register2Property(flowRuleDs.getProperty());
}
}
3.在Nacos中编写规则
4. 进行测试,发现配置成功
5. 使用集成方式利用nacos编写规则
1.在nacos中设置规则(上述已经设置)
2.在配置文件中进行编辑
在application.properties
#使用nacos编辑规则方便Sentinel熔断降级机制的使用
spring.cloud.sentinel.datasource.dsl.nacos.serverAddr=127.0.0.1
spring.cloud.sentinel.datasource.dsl.nacos.dataId=Springboot-sentinel
spring.cloud.sentinel.datasource.dsl.nacos.groupId=SENTINEL_GROUP
spring.cloud.sentinel.datasource.dsl.nacos.dataType=json
spring.cloud.sentinel.datasource.dsl.nacos.ruleType=flow
spring.cloud.sentinel.datasource.dsl.nacos.username=nacos
spring.cloud.sentinel.datasource.dsl.nacos.password=nacos
3、流控规则显示成功
七、使用集群的方式限制流量规则
1.集群示意图
2.建立project sentinel-token-sever
3.添加依赖
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.chaoxing.sentinel</groupId>
<artifactId>sentinel-token-sever</artifactId>
<version>1.0-SNAPSHOT</version>
<name>sentinel-token-sever</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-cluster-server-default</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.0</version>
</dependency>***
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
4.建立服务类ClusterService
public class ClusterServer {
public static void main(String[] args) throws Exception {
ClusterTokenServer tokenServer = new SentinelDefaultTokenServer();
//手动载入namespace和ClusterServerConfigManager
//集群限制流服务端通信相关配置
ClusterServerConfigManager.loadGlobalTransportConfig(new ServerTransportConfig().setIdleSeconds(600).setPort(9999));
//加载namespace集合列表
ClusterServerConfigManager.loadServerNamespaceSet(Collections.singleton("APP-Test"));
tokenServer.start();
//Token-client会上报自己的project.name到token-server会根据namespace来统一
}
}
5.建立获取配置类FlowRuleInitFunc
public class FlowRuleInitFunc implements InitFunc {
private final String nacosAddress = "127.0.0.1:8848";
private final String groupId = "SENTINEL_GROUP";
private final String dataId ="-flow-rules";
@Override
/**
*定义限流规则,初始化规则方便使用
*/
public void init() throws Exception {
ClusterFlowRuleManager.setPropertySupplier(namespace->{
ReadableDataSource<String,List<FlowRule>> flowRuleDs =
new NacosDataSource<List<FlowRule>>(nacosAddress,groupId,namespace+dataId,
s -> JSON.parseObject(s,new TypeReference<List<FlowRule>>(){}));
return flowRuleDs.getProperty();
});
}
}
6.添加从nacos获取配置的配置文件
7. 添加VM
-Dcsp.sentinel.dashboard.server=127.0.0.1:8080 -Dproject.name=sentinel-token-sever
8.在nacos中配置
9.运行
10.客户端连接
public class FlowRuleInitFunc implements InitFunc {
private final String nacosAddress = "127.0.0.1:8848";
private final String groupId = "SENTINEL_GROUP";
private final String dataId ="-flow-rules";
private final String clusterServerHost="localhost";
private final int clusterServerPort=9999;
private final int requestTimeOut=20000;
private final String appname = "App-Test";
@Override
/**
*定义限流规则,初始化规则方便使用
*/
public void init() throws Exception {
loadClusterConfig();
registerFlowRule();
}
private void loadClusterConfig(){
ClusterClientAssignConfig assignConfig = new ClusterClientAssignConfig();
assignConfig.setServerHost(clusterServerHost);//放到配置中心
assignConfig.setServerPort(clusterServerPort);
ClusterClientConfigManager.applyNewAssignConfig(assignConfig);
ClusterClientConfig clientConfig = new ClusterClientConfig();
clientConfig.setRequestTimeout(requestTimeOut);//放到配置中心
ClusterClientConfigManager.applyNewConfig(clientConfig);
}
private void registerFlowRule(){
ReadableDataSource<String,List<FlowRule>> flowRuleDs =
new NacosDataSource<List<FlowRule>>(nacosAddress,groupId,appname+dataId,
s -> JSON.parseObject(s,new TypeReference<List<FlowRule>>(){}));
FlowRuleManager.register2Property(flowRuleDs.getProperty());
}
}
11.设置主方法为客户端
@SpringBootApplication
public class SpringbootSentinelApplication {
public static void main(String[] args) {
ClusterStateManager.applyState(ClusterStateManager.CLUSTER_CLIENT); //表示是客户端
SpringApplication.run(SpringbootSentinelApplication.class, args);
}
}
12.调试vm options(名字要相同)
-Dsever.port=8888 -Dproject.name=App-Test -Dcsp.sentinel.dashboard.server=127.0.0.1:8080
13.确定配置文件可用
14.运行测试
连接成功