规则管理及推送
一般来说,规则的推送有下面三种模式:
| 推送模式 | 说明 | 优点 | 缺点 |
|---|---|---|---|
| 原始模式 | API 将规则推送至客户端并直接更新到内存中,扩展写数据源(WritableDataSource) | 简单,无任何依赖 | 不保证一致性;规则保存在内存中,重启即消失。严重不建议用于生产环境 |
| Pull 模式 | 扩展写数据源(WritableDataSource),客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件等 | 简单,无任何依赖;规则持久化 | 不保证一致性;实时性不保证,拉取过于频繁也可能会有性能问题。 |
| Push 模式 | 扩展读数据源(ReadableDataSource),规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。生产环境下一般采用 push 模式的数据源。 | 规则持久化;一致性;快速 | 引入第三方依赖 |
原始模式
如果不做任何修改,Dashboard 的推送规则方式是通过 API 将规则推送至客户端并直接更新到内存
这种做法的好处是简单,⽆依赖;坏处是应⽤重启规则就会消失,仅⽤于简单测试,不能⽤于⽣产环 境
11.2 Pull 模式
pull 模式的数据源(如本地文件、RDBMS 等)一般是可写入的。使用时需要在客户端注册数据源:将对应的读数据源注册至对应的 RuleManager,将写数据源注册至 transport 的WritableDataSourceRegistry中。
以本地文件数据源为例:
1. 注册数据源
import com.alibaba.csp.sentinel.datasource.FileRefreshableDataSource; import com.alibaba.csp.sentinel.datasource.FileWritableDataSource; import com.alibaba.csp.sentinel.datasource.ReadableDataSource; import com.alibaba.csp.sentinel.datasource.WritableDataSource; import com.alibaba.csp.sentinel.init.InitFunc; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; import java.io.File; import java.io.IOException; import java.util.List; public class FileDataSourceInit implements InitFunc { @Override public void init() throws Exception { String ruleDir = System.getProperty("user.home") + "/sentinel/rules/orderService"; String flowRulePath = ruleDir + "/flow-rule.json"; mkdirIfNotExist(ruleDir); createFileIfNotExist(flowRulePath); // 注册一个可读数据源,用来定时读取本地的json文件,更新到规则缓存中 ReadableDataSource<String, List<FlowRule>> ds = new FileRefreshableDataSource<>( flowRulePath, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() { }) ); // 将可读数据源注册至FlowRuleManager // 这样当规则文件发生变化时,就会更新规则到内存 FlowRuleManager.register2Property(ds.getProperty()); WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>( flowRulePath, this::encodeJson ); // 将可写数据源注册至transport模块的WritableDataSourceRegistry中 // 这样收到控制台推送的规则时,Sentinel会先更新到内存,然后将规则写入到文件中 WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS); } private <T> String encodeJson(T t) { return JSON.toJSONString(t); } private void mkdirIfNotExist(String filePath) throws IOException { File file = new File(filePath); if (!file.exists()) { file.mkdirs(); } } private void createFileIfNotExist(String filePath) throws IOException { File file = new File(filePath); if (!file.exists()) { file.createNewFile(); } } }官方源代码:
2. 在 resources 下创建 META-INF/services 目录
并创建文件:com.alibaba.csp.sentinel.init.InitFunc,写入本地数据源的路径:
com.xxx.xxx.FileDataSourceInitcom.ytvc.order.sentinel.FileDataSourceInit重启服务,设置流控,会发现流控规则同步到指定的文件中。文件路径示例:
C:\用户\lucf\sentinel\rules\orderService\flow-rule.json再次重启服务,规则依然保存(需要请求一下,规则才可以看到)
修改配置文件,可以看到控制台也得到了更新。
配置文件说明(JSON 示例)
[ { // 资源名 "resource": "/test", // 针对来源,若为 default 则不区分调用来源 "limitApp": "default", // 限流阈值类型(1:QPS;0:并发线程数) "grade": 1, // 阈值 "count": 1, // 是否是集群模式 "clusterMode": false, // 流控效果(0:快速失败;1:Warm Up(预热模式);2:排队等待) "controlBehavior": 0, // 流控模式(0:直接;1:关联;2:链路) "strategy": 0, // 预热时间(秒,预热模式需要此参数) "warmUpPeriodSec": 10, // 超时时间(排队等待模式需要此参数) "maxQueueingTimeMs": 500, // 关联资源、入口资源(关联、链路模式) "refResource": "rrr" } ]本地⽂件数据源会定时轮询⽂件的变更,读取规则。这样我们既可以在应⽤本地直接修改⽂件来更新 规则,也可以通过Sentinel控制台推送规则。以本地⽂件数据源为例,推送过程如下图所⽰:
⾸先Sentinel控制台通过API将规则推送⾄客⼾端并更新到内存中,接着注册的写数据源会将新的规 则保存到本地的⽂件中。使⽤pull模式的数据源时⼀般不需要对Sentinel控制台进⾏改造。
这种实现⽅法好处是简单,不引⼊新的依赖,坏处是⽆法保证监控数据的⼀致性(就是需要自己再刷新一下)
11.3 Push 模式
生产环境下一般更常用的是 push 模式的数据源。对于 push 模式的数据源,如远程配置中心(ZooKeeper, Nacos, Apollo 等等),推送的操作不应由 Sentinel 客户端进行,而应该经控制台统一进行管理,直接进行推送,数据源仅负责获取配置中心推送的配置并更新到本地。因此推送规则正确做法应该是配置中心控制台/Sentinel 控制台 → 配置中心 → Sentinel 数据源 → Sentinel,而不是经 Sentinel 数据源推送至配置中心。这样的流程就非常清晰了:
Sentinel 官方提供了 ZooKeeper, Redis, Nacos, Apollo, etcd等的动态数据源实现,参考:dynamic-rule-configuration | Sentinel
接下来以 Nacos 为例来讲解.
参考官方案例:Sentinel/sentinel-extension/sentinel-datasource-nacos at master · alibaba/Sentinel
① 规则下发:控制台 → 配置中心
Sentinel Dashboard(或配置中心控制台)会把你配置的限流 / 熔断规则,写入远程配置中心(比如 Nacos、ZooKeeper)。
- 这一步的核心是「统一存储」:规则不再存在某个客户端的内存或本地文件里,而是集中存放在配置中心。
- 好处:所有实例共享同一份配置,天然保证了集群内的规则一致性。
② 变更监听:配置中心 → 客户端 Sentinel DataSource
每个机器上的Sentinel DataSource会持续监听配置中心的规则变更:
- 当配置中心里的规则更新后,会主动推送变更通知给所有客户端;
- 客户端收到通知后,会拉取最新的规则内容。
③ 规则生效:DataSource → RuleManager(内存)
客户端拉取到最新规则后,会把规则更新到RuleManager中:
RuleManager就是 Sentinel 的内存规则管理器,限流判断时直接读取这里的规则;- 这一步完成后,新规则就会立刻在当前机器上生效,拦截请求。
下载的路径:Releases · alibaba/Sentinel
解压进行源码的改造
11.3.1 Nacos 官方支持
依然是借助 Sentinel 的InitFuncSPI 扩展接口。只需要实现自己的InitFunc接口,在init方法中编写注册数据源的逻辑。
添加依赖
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency>注册数据源
import com.alibaba.csp.sentinel.datasource.ReadableDataSource; import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource; import com.alibaba.csp.sentinel.init.InitFunc; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; import java.util.List; public class NacosDataSourceInit implements InitFunc { // nacos server ip private static final String remoteAddress = "47.108.157.13:8848"; // nacos group private static final String groupId = "SENTINEL_GROUP"; // nacos dataId private static final String dataId = "orderservice-flow-rules"; @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()); } }配置数据源路径
在resources下创建META-INF/services目录,并创建文件:com.alibaba.csp.sentinel.init.InitFunc,文件中写入你实现类的全限定名:
com.bite.order.sentinel.NacosDataSourceInit配置 Nacos
配置内容
[ { "clusterMode": false, "controlBehavior": 0, "count": 88.0, "grade": 1, "limitApp": "default", "maxQueueingTimeMs": 500, "resource": "/order/{orderId}", "strategy": 0, "warmUpPeriodSec": 10 } ]验证结果
重启服务,会发现 Sentinel Dashboard 已经从 nacos 获取规则配置信息了。
- 修改 Nacos 文件,发现 Sentinel Dashboard 会及时更新
- 通过 Sentinel Dashboard 修改规则,发现 Nacos 配置文件并没有同步更新。
11.4 Sentinel 集成 Nacos 持久化
上述我们发现,Nacos 修改的内容会及时同步到 Sentinel DashBoard,但是 Sentinel DashBoard 更新的内容,并不会同步到 Nacos,这在生产环境中,也是不方便使用的。所以我们需要修改 Sentinel 的源码,让其⽀持双向通讯