🙏废话不多说系列,直接开整🙏
一、Sentinel 的工作流程图
Sentinel 的设计理念 是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。
(1)Sentinel 是如何工作的?
Sentinel 的主要工作机制如下:
- 对主流框架提供适配或者显示的 API,来定义需要保护的资源,并提供设施对资源进行实时统计和调用链路分析;
- 根据预设的规则,结合对资源的实时统计信息,对流量进行控制。同时,Sentinel 提供开放的接口,方便你定义以及改变规则;
- Sentinel 提供实时的监控系统,方便你快速了解目前的系统的状态。
(2)Sentinel 功能有哪些?
① 流量控制
流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:
流量控制有以下几个角度:- 资源的调用关系;(例如:调用链路,资源和资源之间的关系)
- 运行指数;(例如:QPS,线程池,系统负载等)
- 控制的效果;(例如:直接限流,冷启动,排队等)
② 熔断降级
除了流量控制以外,降低调用链路的不稳定的资源也是 Sentinel 的使用之一,由于调用链路关系复杂,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。
Sentinel 和 Hystrix 的原则是一致的:
当调用链路中某个资源出现不稳定,例如,表现为 timeout,异常比例升高的时候,则对这个资源的调用进行限制,并让请求快速失败,避免影响到其它的资源,最终产生雪崩的效果。
Sentinel 对熔断降级的实现方案:
- 通过并发线程数进行限制;
- 通过响应时间对资源进行降级;
③ 系统负载保护
Sentinel 同时提供系统维度的自适应保护能力。防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。
针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。
来源: https://sentinelguard.io/zh-cn/docs/introduction.html
二、Sentinel 初体验
(1)创建一个 SpringBoot工程
使用 创建Alibaba的创建 Spring Boot的镜像;
(2)引入 Sentinel 依赖
<!-- 核心依赖:sentinel流量防卫机制-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.0</version>
</dependency>
<!-- 支持 sentinel 注解开发机制 ,还有很多的 sentinel 的开发机制-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.8.0</version>
</dependency>
(3)编写测试控制层接口
package edu.study.module.up.controller;
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 javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
/**
* @author zl
* @create 2021-08-21 17:57
*/
@RestController
@RequestMapping(value = "/sentinel/demo")
public class SentinelController {
// 测试接口:当QPS限流值达到设置值后将会触发BlockException异常从而达到限流效果。
@GetMapping("/limit")
public String limit() {
try {
// 使用[资源](在限流规则中定义的资源名称)
Entry entry =SphU.entry("limit");
return "hello sentinel limited";
} catch (BlockException e) {
e.printStackTrace();
return "系统繁忙";
}
}
// 定义限流规则
@PostConstruct
public void initRules() {
// 1.创建存放限流规则的集合
List<FlowRule> rules = new ArrayList<>();
// 2.创建限流规则
FlowRule rule = new FlowRule();
// 3.定义资源,表示Sentinel会对哪些个【资源】(也就是一般为具体的接口)生效
rule.setResource("limit");
// 4.定义限流规则的类型(限流规则类型常见为QPS)
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 5.设置限流值: Set limit QPS to 3.(请求数量达到一定的则限流)
rule.setCount(3);
rules.add(rule);
// 6.加载规则到限流规则下
FlowRuleManager.loadRules(rules);
}
}
(4)运行测试
当 QPS 达到限定值时将出现此效果
三、本地 Sentinel 控制台搭建
Sentinel 提供了一个轻量级的开源控制台,它提供了机器发现以及健康情况管理、实时监控(单机和集群),规则管理和推送功能。
(1)本地控制台搭建
① 下载地址
https://github.com/alibaba/Sentinel/releases/download/1.8.2/sentinel-dashboard-1.8.2.jar
② 启动 Sentinel 控制台
注意:启动 Sentinel控制台需要 JDK 1.8 以及以上版本。
找到下载好的 Sentinel 的下载目录启动。
java -Dserver.port=9000 -Dcsp.sentinel.dashboard.server=localhost:9000 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.2.jar
看到最后出现: Tomcat started on port(s): 9000 (http) with context path ''即说明服务启动成功
③ 浏览器访问测试 Sentinel-Dashboard
登录用户名和密码欸:sentinel / sentinel
四、本地引用接入到控制台
本地应用是以客户端的身份来接入控制台。
(1)在本地应用的 pom.xml 文件中引入依赖
<!--sentinel接入控制台面板中-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.0</version>
</dependency>
(2)设置服务启动的 JVM 参数
# 设置Sentinel控制台的主机地址和端口
-Dcsp.sentinel.dashboard.server=localhost:9000
# 设置本地应用在 Sentinel 控制台中的名称
-Dproject.name=SentinelQuickStart
(3)运行本地测试
① 再次重新启动应用服务;
② 访问服务应用下限流的接口;(注意:sentinel是不会自动的加入到 sentinel-dashboard中的,需要手动访问才会自动加入的)
http://localhost:8099/sentinel/demo/limit
③ 再次回到 sentinel dashboard 中,接口看到;
④ 至此,初步使用 sentinel 完结。五、本地控制台设置流量规则
前面介绍的时在代码中硬编码的方式设置的每个接口的流量设置方式。现在我们通过 控制台去动态设置流量的阈值。(见动图)
动态设置 阈值,而不是在代码里面“硬编码”方式设置阈值
六、Sentinel定义资源方式:返回布尔值方式定义资源
Sentinel 中的 SphO 提供 if-else 风格的 API。用这种方式,当资源发生了限流之后返回 false,这个时候可以根据返回值,进行限流之后的逻辑处理。
(1)在 sentinel_quick_start 项目中创建 TestBooleanController,在 TestBooleanController 中使用返回布尔值的方式定义资源;
@GetMapping("boolean")
public boolean hello() {
// 1.进行限流控制
if (SphO.entry("Sentinel_Boolean")) {
try {
// 被保护的资源
System.out.println("访问成功");
return true;
} finally {
// 限流出口(SphO.entry(xxx) 需要与 SphO.exit() 方法成对出现,否则会导致调用链记录异常,抛出ErrorEntryFreeException异常)
SphO.exit();
}
} else {
// 被限流或者降级的处理
System.out.println("系统繁忙,请稍等");
return false;
}
}
(2)通过浏览器访问对应接口,刷新 sentinel dashboard 查看
系统输出:
访问成功
访问成功
系统繁忙,请稍等
访问成功
系统繁忙,请稍等
系统繁忙,请稍等
系统繁忙,请稍等
七、Sentinel 定义资源方式:抛出异常方式
- 抛出异常的方式定义资源;
- 返回布尔值方式定义资源;
- 异步调用支持;
- 注解方式定义资源;
- 主流框架的默认适配;
(1)抛出异常
Sentinel 中的 SphU 包含了 try-catch 风格的 API。用这种方式,当资源发生了限流之后会抛出 BlockException 这个时候可以捕捉异常,进行限流之后的逻辑处理,而我们在入门案例中就使用的此种方式进行定义资源,关键代码如下:
try (Entry entry = SphU.entry("Hello")) {
return "Hello Sentinel!"; // 被保护的资源
} catch (BlockException e) {
e.printStackTrace();
return "系统繁忙,请稍后"; // 被限流或者降级的处理
}
(2)返回布尔值方式定义资源
将上面【第六点】
(3)异步调用支持
Sentinel 支持异步调用链路的统计,在异步调用中,需要通过 SphU.asyncEntry(xxx) 方法定义资源,并通常需要在异步的回调函数中调用 exit() 方法。
① 在 启动项目类上添加 @EnableAsync 注解
@EnableAsync
@SpringBootApplication
public class UpApplication {
public static void main(String[] args) {
SpringApplication.run(UpApplication.class, args);
}
}
② 创建 AsyncService 编写异步调用方法
@Override
@Async // 表示此方法为异步调用方法
public void AsyncHello() {
System.out.println("异步开始………………");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("异步结束………………");
}
③ 控制层测试
@GetMapping("/async")
public void asyncHello() {
AsyncEntry asyncEntry = null;
try {
asyncEntry = SphU.asyncEntry("Sentinel_Async");// 限流入口
sentinelTestService.AsyncHello();// 异步方法调用
} catch (BlockException e) { // 被限流或者降级的处理
System.out.println("系统繁忙,请稍后");
} finally {
if (asyncEntry != null) {
asyncEntry.exit();// 限流出口
}
}
}
④ 测试
- 重启服务;
- 浏览器访问对应接口;
- 进入Sentinel Dashboard 对接口设置流控规则;
(4)注解方式定义资源
Sentinel 支持通过 @SentinelResouce 注解定义资源并配置 blockHandler 函数来进行限流之后的处理。
① 引入 maven 依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.8.0</version>
</dependency>
② 创建 AspectJ 的配置类
@Configuration
public class SentinelAspectConfiguration {
@Bean
public SentinelResourceAspect sentinelResourceAspect(){
return new SentinelResourceAspect();
}
}
③ 控制层测试,实现流量控制
@Override
@SentinelResource(value = "hello", fallback = "helloFallback")
public String hello(long s) {
if (s < 0) {
throw new IllegalArgumentException("invalid arg");
}
return String.format("Hello at %d", s);
}
@Override
@SentinelResource(value = "helloAnother", defaultFallback = "defaultFallback", exceptionsToIgnore = {IllegalStateException.class})
public String helloAnother(String name) {
if (name == null || "bad".equals(name)) {
throw new IllegalArgumentException("oops");
}
if ("foo".equals(name)) {
throw new IllegalStateException("oops");
}
return "Hello, " + name;
}
- @SentinelResource 注解用来标识资源是否被限流、降级。
- @SentinelResource 还提供了其他额外的属性如 blockHandler 来指定被限流后的操作。
④ 运行测试
在 Sentinel Dashboard 测试面板中配置 对应的资源流控的配置流控规则。
附录
-
官方Sentinel 地址:home (sentinelguard.io)
-
官方Sentinel 案例:Sentinel/sentinel-demo at master · alibaba/Sentinel · GitHub
-
相关使用博客地址:【学相伴】Sentinel流控与降级实现_狂神说-CSDN博客
🙏至此,非常感谢阅读🙏