Sentinel 动态流控规则

Sentinel 动态流控规则

一、概述

正常情况下,业务开发中,Sentinel的限流或者熔断规则,是配置在项目本地通过SPI扩展点来实现的。而在系统设计的时候,这些模式需要配合业务量的预估、性能测试的数据进行相应阈值的配置,而这些阈值最好保存在配置中心,方便动态实时修改。

二、动态流控规则
Sentinel 的理念是开发者只需要关注资源的定义,当资源定义成功后可以动态增加各种流控降级规则。Sentinel 提供两种方式修改规则:

  • 通过 API 直接修改 ( loadRules )
  • 通过 DataSource 适配不同数据源修改

通过 API 修改比较直观,可以通过以下几个 API 修改不同的规则:

FlowRuleManager.loadRules(List<FlowRule> rules); // 修改流控规则
DegradeRuleManager.loadRules(List<DegradeRule> rules); // 修改降级规则

2.1、动态规则的基本原理

由于loadRules()方法只能接受内存态的规则对象,但是在有一些场景中,限流是一个动态的行为,也就是规则可能存储于文件、数据库、配置中心。通过这种存储方式可以提供sentinel动态限流规则,如下图所示
Sentinel 动态流控规则_第1张图片
2.2、DataSource

Sentinel提供了一个DataSource接口,这个接口为Sentinel提供了对接任意配置源的能力,相比于API的方式来修改规则,实现DataSource接口的方法更加灵活。

DataSource 扩展常见的实现方式有:

  • 拉模式:客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文 件 等。这样做的方式是简单,缺点是无法及时获取变更;
  • 推模式:规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。

Sentinel 目前支持以下数据源扩展:

  • Pull-based: 动态文件数据源、Consul, Eureka
  • Push-based: ZooKeeper, Redis, Nacos, Apollo, etcd

拉模式拓展 实现拉模式的数据源最简单的方式是继承 AutoRefreshDataSource 抽象类,然后实现readSource() 方法,在该方法里从指定数据源读取字符串格式的配置数据。比如 基于文件的数据源。

推模式拓展 实现推模式的数据源最简单的方式是继承 AbstractDataSource 抽象类,在其构造方法中添加监听器,并实现 readSource() 从指定数据源读取字符串格式的配置数据。比如 基于 Nacos 的数据源。

规则的感知( Pull 、Push)流程图如下
Sentinel 动态流控规则_第2张图片

三、SPI 动态数据源demo

3.1、Sentinel的InitFunc SPI来实现接口的扩展,从而配置限流规则

public class FlowRuleInitFunc implements InitFunc{
@Override
public void init() throws Exception {
List<FlowRule> rules=new ArrayList<>();
FlowRule rule=new FlowRule();
rule.setResource("doTest");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(5);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
}

在META-INF/services/com.alibaba.csp.sentinel.init.InitFunc文件中,添加自定义扩展点的全路径

3.2、扩展Nacos数据源

//添加Nacos Datasouce pom依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.8.0</version>
</dependency>

修改数据源加载方式(于SPI扩展的InitFunc来实现的)

public class DataSourceInitFunc implements InitFunc{
private final String remoteAddress="192.168.149.28"; //Nacos 远程服务host
private final String groupId="SENTINEL_GROUP"; //Nacos GroupID
private final String dataId="com.sentinel.demo.flow.rule";
@Override
public void init() throws Exception {
ReadableDataSource<String,List<FlowRule>> flowRuleDataSource=
new NacosDataSource<>(remoteAddress,groupId,dataId,
source-> JSON.parseObject(source,new
TypeReference<List<FlowRule>>(){}));
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
}
}

在Nacos上添加配置

Sentinel 动态流控规则_第3张图片

四、配置文件的demo

spring.cloud.sentinel.transport.clientIp=192.168.149.28:7777
spring.cloud.sentinel.datasource.nacos.nacos.serverAddr=192.168.149.28:8848
spring.cloud.sentinel.datasource.nacos.nacos.dataId=com.sentinel.demo.flow.rule
spring.cloud.sentinel.datasource.nacos.nacos.groupId=SENTINEL_GROUP
spring.cloud.sentinel.datasource.nacos.nacos.dataType=json
spring.cloud.sentinel.datasource.nacos.nacos.ruleType=flow
spring.cloud.sentinel.datasource.nacos.nacos.username=nacos
spring.cloud.sentinel.datasource.nacos.nacos.password=nacos

五、集群限流

通常工作中只是基于Sentinel的基本使用和单机限流的使用,集群限流场景很少。

假如有这样一个场景,我们现在把provider部署了10个集群,希望调用这个服务的api的总的qps是100,意味着每一台机器的qps是10,理想情况下总的qps就是100,但是实际上由于负载均衡策略的流量分发并不是非常均匀的,就会导致总的qps不足100时,就被限了。在这个场景中,仅仅依靠单机来实现总体流量的控制是有问题的。所以最好是能实现集群限流。

集群流控中共有两种身份:

  • Token Client:集群流控客户端,用于向所属 Token Server 通信请求token。集群限流服务端会返回给客户端结果,决定是否限流。
  • Token Server:即集群流控服务端,处理来自 Token Client 的请求,根据配置的集群规则判断是否应该发放 token(是否允许通过)

Sentinel 动态流控规则_第4张图片

你可能感兴趣的:(spring,cloud,nacos,Sentinel,微服务)