Sentinel功能简介:
流控普适场景
- Provider端控制脉冲流量
- 针对不同调用来源进行流控
- Web接口流控
Sentinel限流控制
- 通过硬编码方式进行限流控制
// 定义限流规则
@PostConstruct
public void initFlowRules() {
// 创建存放限流规则的集合
List<FlowRule> rules = new ArrayList<>();
// 创建限流规则
FlowRule rule = new FlowRule();
// 定义资源,标识Sentinel会对哪个资源生效
rule.setResource("HelloResource1");
// 定义限流规则类型 QPS限流类型
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 定义QPS每秒能通过的请求个数
rule.setCount(2.0);
// 将限流规则存放到集合中
rules.add(rule);
// 加载限流规则
FlowRuleManager.loadRules(rules);
}
- 通过Sentinel 控制台的方式来进行限流控制:https://sentinelguard.io/zh-cn/docs/dashboard.html
流控模式
基于调用关系的流量控制,调用关系包括调用方,被调用方;一个方法可能会调用其它方法,形成一个调用链路的层次关系。
关联:当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。比如对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写得速束度,写的速度过高会影响读的速度。如果放任读写操作争抢资源,则争抢本身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢,举例来说,read_db
和write_db
这两个资源分别代表数据库读写,我们可以给read_db
设置限流规则来达到写优先的目的:设置strategy
为Ru leConstant.STRATEGY_RELATE
同时设置refResource
为write_db
。这样当写库操作过于频繁时,读数据的请求会被限流。
链路:根据调用链路入口限流
流控效果
快速失败:(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException
。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。
激增流量:Warm Up (RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热冷启动方式。当系统长期处于低水位的情况下,流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过『冷启动』,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
冷加载因子:codeFactor默认是3,即请求 QPS 从threshold / 3
开始,经预热时长逐渐升至设定的 QPS 阈值。
匀速排队:(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER
)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。这种方式主要用于处理间隔性突发的流量,例如消息队列。
Sentinel资源定义
- 抛出异常的方式定义资源
/**
* 抛出异常的方式定义资源
* Sentinel中的SphU包含了try-catch风格的API。用这种方式,当资源翻身了限流之后会抛出BlockException。这个时候可以捕获异常,进行限流之后的逻辑处理。
*/
@GetMapping("/hello1")
public String hello1() {
// 限流入口
// 使用限流规则监控保护资源
try (Entry entry = SphU.entry("HelloResource1")) {
LocalDateTime now = LocalDateTime.now();
// 被保护的资源
return "Hello, Now is " + dateTimeFormatter.format(now);
} catch (BlockException exception) {
exception.printStackTrace();
log.error("Exception is : {}", exception);
// 被限流或是被降级的操作处理
return "系统繁忙,请稍候重试";
}
}
- 返回布尔值方式定义资源
/**
* 返回Boolean值方式定义资源
* Sentinel中的SphO提供if-else风格的API。用这种方式,当资源发生了限流之后会返回false,这个时候可以根据返回值,进行限流之后的逻辑处理
* SphO.entry()需要与SphO.exit()方法成对出现,否则会导致调用链记录异常,抛出ErrorEntryFreeException
*/
@GetMapping("/hello2")
public String hello2() {
// 进行限流控制,限流入口
if (SphO.entry("HelloResource2")) {
try {
// 被保护的资源
log.info("访问成功");
return "Hello, Now is " + dateTimeFormatter.format(LocalDateTime.now());
} finally {
// 限流出口
SphO.exit();
}
} else {
// 被限制或者降级的处理
log.info("系统繁忙,请稍候重试");
return "系统繁忙,请稍候重试";
}
}
- 异步调用支持
先定义异步Service,并开启异步
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;
@Service
@Slf4j
public class HelloService {
private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Async
public void hello3() {
log.info("异步开始: {}", dateTimeFormatter.format(LocalDateTime.now()));
try {
TimeUnit.SECONDS.sleep(2L);
} catch (InterruptedException exception) {
log.error("exception is {}", exception);
}
log.info("异步结束: {}", dateTimeFormatter.format(LocalDateTime.now()));
}
}
/**
* 异步调用支持
* Sentinel支持异步调用链路的统计。在异步调用中,需要通过SphU.asyncEntry()方法定义资源,并通常需要在异步的回调函数中调用exit方法
*/
@GetMapping("/hello3")
public String hello3() {
// 进行限流控制
AsyncEntry asyncEntry = null;
try {
// 限流入口
asyncEntry = SphU.asyncEntry("HelloResource3");
// 异步方法调用
helloService.hello3();
return "Hello, Now is " + dateTimeFormatter.format(LocalDateTime.now());
} catch (BlockException exception) {
// 被限流或者降级的处理
return "系统繁忙,请稍候重试";
} finally {
if (Objects.nonNull(asyncEntry)) {
// 限流出口
asyncEntry.exit();
}
}
}
- 注解方式定义资源
需要引入依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.7.2</version>
</dependency>
配置SentinelResourceAspect
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SentinelAspectJConfiguration {
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
/**
* 注解方式定义资源
* Sentinel支持通过@SentinelResource注解定义资源并配置blockHandler函数来进行限流之后的处理
*/
@GetMapping("/hello4")
// 定义限流资源和限流降级回调函数
@SentinelResource(value = "HelloResource4", blockHandler = "exceptionHandler")
public String hello4() {
return "Hello, Now is " + dateTimeFormatter.format(LocalDateTime.now());
}
/**
* blockHandler函数,原方法调用被限流/降级/系统保护时候被调用
* 一定要public
* 返回值一定要和原方法保持一致
* 包含原方法的参数,可以在参数最后添加BlockException异常类,BlockException可以区分是什么规则的处理方法
*/
public String exceptionHandler(BlockException exception) {
log.error("exception is {}", exception);
return "系统繁忙,请稍候重试";
}
@SentinelResource 注解支持的属性:https://sentinelguard.io/zh-cn/docs/annotation-support.html
完整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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lwy.it</groupId>
<artifactId>sentinel-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sentinel-demo</name>
<description>Demo project for Spring Boot Sentinel</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.5</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.5</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.8.5</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
更多学习参考官方文档:https://sentinelguard.io/zh-cn/docs/quick-start.html
Sentinel熔断降级
熔断策略
Sentinel 提供以下几种熔断策略:
- 慢调用比例 (
SLOW_REQUEST_RATIO
):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs
)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。 - 异常比例 (
ERROR_RATIO
):当单位统计时长(statIntervalMs
)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是[0.0, 1.0]
,代表 0% - 100%。 - 异常数 (
ERROR_COUNT
):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
使用注解方式定义资源:
@GetMapping("/degrade")
@SentinelResource(value = "degrade", fallback = "degradeFallback")
public String degrade(@RequestParam("num") int number) {
LocalDateTime now = LocalDateTime.now();
try {
TimeUnit.SECONDS.sleep(1L);
} catch (InterruptedException e) {
e.printStackTrace();
}
double result = 100 / number;
return "result: " + result + " now is " + dateTimeFormatter.format(now);
}
// 降级方法
public String degradeFallback(int number, Throwable throwable) {
return number + "发生异常!" + throwable.getMessage();
}
/**
* 一分钟内:执行2次,出现了2次异常,就会触发熔断,熔断时间10s
*/
@PostConstruct
public void initDegradeRule() {
List<DegradeRule> rules = new ArrayList<>();
DegradeRule degradeRule = new DegradeRule();
degradeRule.setResource("degrade");
// 设置规则策略:异常数
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
// 设置阈值
degradeRule.setCount(2.0);
// 设置触发熔断最小请求数
degradeRule.setMinRequestAmount(2);
// 统计时长,在多长时间内触发的两次异常导致熔断,单位:毫秒
degradeRule.setStatIntervalMs(60000);
// 熔断持续时长,单位:秒
// 一旦触发了熔断,再次请求对应的接口就会直接调用降级方法
// 10秒过了后进入半开状态,恢复接口调用,如果第一次请求就异常,再次进入熔断。不会根据设置的条件进行判定
degradeRule.setTimeWindow(10);
rules.add(degradeRule);
DegradeRuleManager.loadRules(rules);
}
使用硬编码方式:
注意异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException
)不生效。为了统计异常比例或异常数,需要通过 Tracer.trace(ex)
记录业务异常。
@GetMapping("/degrade")
public String degrade(@RequestParam("num") int number) {
Entry entry = null;
try {
// 定义资源
entry = SphU.entry("degrade");
TimeUnit.SECONDS.sleep(1L);
double result = 100 / number;
return "result:" + result + "! now is " + dateTimeFormatter.format(LocalDateTime.now());
} catch (Throwable throwable) {
if (!BlockException.isBlockException(throwable)) {
Tracer.trace(throwable);
}
return "发生异常!" + throwable.getMessage();
} finally {
if (entry != null) {
entry.exit();
}
}
}
/**
* 一分钟内:执行2次,出现了2次异常,就会触发熔断,熔断时间10s
*/
@PostConstruct
public void initDegradeRule() {
List<DegradeRule> rules = new ArrayList<>();
DegradeRule degradeRule = new DegradeRule();
degradeRule.setResource("degrade");
// 设置规则策略:异常数
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
// 设置阈值
degradeRule.setCount(2.0);
// 设置触发熔断最小请求数
degradeRule.setMinRequestAmount(2);
// 统计时长,在多长时间内触发的两次异常导致熔断,单位:毫秒
degradeRule.setStatIntervalMs(60000);
// 熔断持续时长,单位:秒
// 一旦触发了熔断,再次请求对应的接口就会直接调用降级方法
// 10秒过了后进入半开状态,恢复接口调用,如果第一次请求就异常,再次进入熔断。不会根据设置的条件进行判定
degradeRule.setTimeWindow(10);
rules.add(degradeRule);
DegradeRuleManager.loadRules(rules);
}
特别地,若 entry 的时候传入了热点参数,那么 exit 的时候也一定要带上对应的参数(exit(count, args)
),否则可能会有统计错误。这个时候不能使用 try-with-resources 的方式。另外通过 Tracer.trace(ex)
来统计异常信息时,由于 try-with-resources 语法中 catch 调用顺序的问题,会导致无法正确统计异常数,因此统计异常信息时也不能在 try-with-resources 的 catch 块中调用 Tracer.trace(ex)
。
注意: SphU.entry(xxx)
需要与 entry.exit()
方法成对出现,匹配调用,否则会导致调用链记录异常,抛出 ErrorEntryFreeException
异常。
降级规则
除了流量控制以外,对调用链路中不稳定的资源进行熔断经济也是保障高可用的重要措施之一 。我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。
保护自身的手段(通常在consumer
端组合配置)
- 并发控制(信号量隔离)
- 基于慢调用比例熔断
- 基于异常比例熔断
触发熔断后的处理逻辑示例
- 提供fallback实现(服务降级)
- 返回错误result
- 度缓存(DB访问降级)
熔断降级规则(DegradeRule)包含下面几个重要的属性:
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名,即规则的作用对象 | |
grade | 熔断策略,支持慢调用比例/异常比例/异常数策略 | 慢调用比例 |
count | 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值 | |
timeWindow | 熔断时长,单位为 s | |
minRequestAmount | 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入) | 5 |
statIntervalMs | 统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入) | 1000 ms |
slowRatioThreshold | 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入) |
BlockException异常统一处理
SpringWebMVC接口资源限流入口在HandlerInterceptor的实现类AbstractSentinelInterceptor
的preHandler
方法中,对异常的处理是BlockExceptionHandler
的实现类
整合Spring框架
添加依赖,版本参照Spring Cloud Alibaba对应版本
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2021.0.1.0</version>
</dependency>
application.properties配置:
# 设置应用的名称
spring.application.name=SpringCloudSentinelDemo
# 设置Sentinel连接控制台的主机地址和端口
spring.cloud.sentinel.transport.dashboard=localhost:9000
编写测试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.RestController;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@RestController
@Slf4j
public class HelloController {
private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 定义限流资源和限流降级回调函数
@SentinelResource(value = "HelloResource_1", blockHandler = "exceptionHandler")
@GetMapping("/hello1")
public String hello1() {
return "Hello World, Time is " + dateTimeFormatter.format(LocalDateTime.now());
}
// blockHandler函数,用于降级时调用
public String exceptionHandler(BlockException exception) {
log.error("Exception: {}", exception);
return "系统繁忙,请稍候!";
}
}
Sentinel整合OpenFeign
准备工作见:https://blog.csdn.net/liwenyang1992/article/details/126167210
与Hystrix类似。
配置文件打开Sentinel对OpenFeign的支持
# 打开Sentinel对OpenFeign的支持
feign.sentinel.enabled=true
# 注册中心
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
# Spring Boot 默认日志级别是info,feign的debug日志级别就不会输入
logging.level.com.lwy.it.feign=debug
# 开启请求GZIP
feign.compression.request.enabled=true
# 开启响应GZIP
feign.compression.response.enabled=true
# 设置支持GZIP压缩的MIME类型,即请求/响应类型
feign.compression.request.mime-types=text/xml,application/xml,application/json
# 配置启动压缩数据量的最小阈值,单位字节。默认为2014
feign.compression.request.min-request-size=1024
添加OpenFeign及注册中心的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>3.1.3</version>
</dependency>
OpenFeign配置类
import feign.Logger;
import org.springframework.context.annotation.Bean;
// @Configuration
// 注意:此处使用@Configuration注解就会全局生效,如果想指定对应微服务生效,就不能配置
public class FeignConfiguration {
/**
* 日志级别:
* NONE:默认值,性能最佳,适用于生产环境,不记录任何日志
* BASIC: 适用于生产环境问题追踪,仅记录请求方法、URL、响应状态代码以及执行时间
* HEADERS:在BASIC基础上增加请求和响应header
* FULL:比较适合开发及测试环境定位,记录请求和响应的header、body和元数据
*/
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
OpenFeign访问接口服务,RPC调用,可以看出与Hystrix用法类似
import com.lwy.it.config.FeignConfiguration;
import com.lwy.it.vo.BookVO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;
/**
* name 指定调用rest接口所对应的服务名
* path 指定调用rest接口所在Controller指定的@RequestMapping
* configuration 局部配置,让调用的微服务生效,在@FeignClient注解中指定使用的配置类
* fallback:与Hystrix类似,配置降级方案
*/
@FeignClient(value = "demo-server", path = "/server/book", configuration = FeignConfiguration.class, fallback = BookFeignFallbackService.class)
public interface BookFeignService {
@GetMapping("/list")
List<BookVO> getAllBooks();
}
提供降级方案:
import com.lwy.it.vo.BookVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.List;
/**
* BookFeignFallbackService作为流控降级回调类,并在BookFeignService进行流控降级回调配置
*/
@Slf4j
@Component
public class BookFeignFallbackService implements BookFeignService {
// 限流和降级的处理
@Override
public List<BookVO> getAllBooks() {
log.warn("进入降级方法");
return Collections.emptyList();
}
}
编写Controller验证:
import com.lwy.it.feign.BookFeignService;
import com.lwy.it.vo.BookVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/book")
public class BookController {
@Autowired
private BookFeignService bookFeignService;
@GetMapping("/list")
public List<BookVO> getAllBooks() {
return bookFeignService.getAllBooks();
}
}
启动项目,在Sentinel控制台中新增流控规则,Sentinel与OpenFeign整合时。流控规则的编写形势为:
http请求方式:请求协议//服务名/请求路径跟参数
例如:
GET:http://demo-server/server/book/list
热点参数限流
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的数据,并对其访问进行限制。
热点规则,必须使用@SentinelResource注解。
单机阈值
- 假设参数大部分都是热点参数,那单机阈值就主要针对热点参数进行流控,后续额外对普通参数进行流控
- 假设大部分值都是普通流量,那单机阈值就主要针对普通参数进行流控,热点参数进行额外流控
系统保护规则
容量评估不到位,某个大流量接口限流配置不合理或没有配置,导致系统崩溃,来不及进行处理。
突然发现机器的Load 和CPUusage等开始飚高,但却没有办法很快的确认到是什么原因造成的,也来不及处理。
当其中一台机器挂了之后,本该由这台机器处理的流量被负载均衡到另外的机器上,另外的机器也被打挂了,引起系统雪崩。
希望有个全局的兜底防护,即使缺乏容量评估也希望有一定的保护机制。
Sentinel系统自适应限流从整体维度对应用入口流量进行控制,结合应用的Load
、CPU使用率
、总体平均RT
、入口QPS
和并发线程数
等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
- Load自适应(仅对 Linux/Unix-like 机器生效):系统的load1作为启发指标,进行自适应系统保护。当系统load1超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR阶段)。系统容量由系统的
maxQps * minRt
估算得出。 设定参考值一般是CPU cores * 2.5
。
参考:https://www.cnblogs.com/gentlemanhai/p/8484839.html - CPU usage(1.5.0+版本):当系统CPU使用率超过阈值即触发系统保护(取值范围0.0~1.0),比较灵敏。
- 平均RT:当单台机器上所有入口流量的平均 RT达到阈值即触发系统保保护,单位是毫秒。
- 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
- 入口 QPS:当单台机器上所有入口流量的 QPS达到阈值即触发系统保保护。
Sentinel持久化
DataSource
扩展常见的实现方式有:
- 拉模式:客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件,甚至是 VCS 等。这样做的方式是简单,缺点是无法及时获取变更;
- 推模式:规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。
Sentinel 目前支持以下数据源扩展:
拉模式扩展
实现拉模式的数据源最简单的方式是继承 AutoRefreshDataSource
抽象类,然后实现 readSource()
方法,在该方法里从指定数据源读取字符串格式的配置数据。比如 基于文件的数据源。
推模式扩展
实现推模式的数据源最简单的方式是继承 AbstractDataSource
抽象类,在其构造方法中添加监听器,并实现 readSource()
从指定数据源读取字符串格式的配置数据。比如 基于 Nacos 的数据源。
参考:https://sentinelguard.io/zh-cn/docs/dynamic-rule-configuration.html
使用 Apollo 配置规则
Sentinel 针对 Apollo 作了相应适配,底层可以采用 Apollo 作为规则配置数据源。使用时只需添加以下依赖:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-apollo</artifactId>
<version>x.y.z</version>
</dependency>
然后创建 ApolloDataSource
并将其注册至对应的 RuleManager 上即可。比如:
// namespaceName 对应 Apollo 的命名空间名称
// ruleKey 对应规则存储的 key
// defaultRules 对应连接不上 Apollo 时的默认规则
ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new ApolloDataSource<>(namespaceName, ruleKey, defaultRules, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {}));
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
详细示例可以参见:https://github.com/alibaba/Sentinel/tree/master/sentinel-demo/sentinel-demo-apollo-datasource