当前位置: 首页 > news >正文

Sentinel规则持久化push模式改造

文章目录

  • 概述
  • 一、push模式的微服务端实现
    • 1.1、NacosWritableDataSource
    • 1.2、ReadableDataSource
  • 二、push模式的Sentinel控制台实现
  • 三、规则转换失效的解决
  • 总结:Sentinel规则持久化的Push模式实现方案
      • 1. 微服务端实现(基于客户端读写数据源)
      • 2. Sentinel控制台服务端实现(基于控制台读写)
    • 流程对比
      • 微服务端模式:
      • Sentinel控制台服务端模式:
    • 方案对比总结


概述

  Sentinel规则持久化有两种模式,一种是前篇中提到的本地存储的pull模式,主要涉及到了FileRefreshableDataSourceFileWritableDataSource。前者的目的是为了定时获取配置文件的改动,并且同步到微服务端的内存。 后者的目的则是将sentinel控制台推送的配置文件,写入到本地磁盘文件或数据库/redis等中间件中。因为微服务端的内存,需要通过定时任务拉取本地的变更病同步,所以称之为拉模式
在这里插入图片描述
  但是这样做,可能存在一定的弊端:

  1. 如果用户直接对本地文件进行的修改,那么同步至少需要3s的时间间隔。
  2. 控制台在推送配置文件时,带有ip和端口。如果sentinel是集群部署,那么控制台只会推送配置文件到集群中的一台服务器上,然后将配置文件存在该台服务器的本地文件中。集群之间还需要数据同步。(存储在mysql或redis中可以解决)

  除去拉模式外,还有一种整合了Nacos的推模式,大体的思路如下图,将配置中心作为sentinel各种规则的管理者。

  1. 用户在sentinel控制台进行规则修改,将规则同步到Nacos配置中心。
  2. 用户在sentinel控制台主动拉取Nacos配置中心的最新配置。

  如果需要进行推模式的改造,有微服务端sentinel服务端的两种改造方案

一、push模式的微服务端实现

  **微服务端(客户端)**的改造,是基于sentinel会将规则推送一份到客户端:
在这里插入图片描述

1.1、NacosWritableDataSource

  客户端 在接收到 服务端推送的配置文件后,除了保存一份到自己的内存外,还需要将该配置信息推送给Nacos配置中心,这里利用到了Nacos的发布配置api,向nacos配置中心写数据:

configService.publishConfig(String dataId, String group, String content, String type)

  在客户端加上:

public class NacosWritableDataSource<T> implements WritableDataSource<T> {private final String serverAddr;private final String groupId;private final String dataId;private final Properties properties;private ConfigService configService;private final Converter<T, String> configEncoder;private final Lock lock = new ReentrantLock(true);public NacosWritableDataSource(String serverAddr, String groupId, String dataId, Converter<T, String> configEncoder) {this.serverAddr = serverAddr;this.groupId = groupId;this.dataId = dataId;this.properties = NacosWritableDataSource.buildProperties(serverAddr);this.configEncoder = configEncoder;initConfigService();}private void initConfigService() {try {this.configService = NacosFactory.createConfigService(properties);} catch (NacosException e) {e.printStackTrace();}}static Properties buildProperties(String serverAddr) {Properties properties = new Properties();properties.setProperty(PropertyKeyConst.SERVER_ADDR, serverAddr);return properties;}@Overridepublic void write(T t) throws Exception {lock.lock();try {//向nacos配置中心写数据configService.publishConfig(dataId, groupId, this.configEncoder.convert(t), ConfigType.JSON.getType());} finally {lock.unlock();}}@Overridepublic void close() throws Exception {}
}

  可以通过SPI机制实现:

public class NacosDataSourceInitFunc implements InitFunc {@Value("${spring.cloud.sentinel.datasource.param-flow-rules.nacos.server-addr}")private String serverAddr;@Value("${spring.cloud.sentinel.datasource.param-flow-rules.nacos.groupId}")private String groupId;@Value("${spring.cloud.sentinel.datasource.param-flow-rules.nacos.dataId}")private String dataId;@Overridepublic void init() throws Exception {//在com.alibaba.csp.sentinel.command.handler.ModifyRulesCommandHandler.writeToDataSource 中被调用WritableDataSource<List<FlowRule>> writableDataSource = new NacosWritableDataSource<>(serverAddr,groupId,dataId, JSON::toJSONString);WritableDataSourceRegistry.registerFlowDataSource(writableDataSource);}
}

在这里插入图片描述
  同时需要在配置文件中加入:

spring:application:name: mall-user-sentinel-rule-push-demo  #微服务名称#配置nacos注册中心地址cloud:nacos:discovery:server-addr: 127.0.0.1:8848sentinel:transport:# 添加sentinel的控制台地址dashboard: 127.0.0.1:8080# 指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer#port: 8719datasource: flow-rules: #名称自定义,唯一nacos:server-addr: 127.0.0.1:8848dataId: ${spring.application.name}-flow-rulesgroupId: SENTINEL_GROUP   # 注意groupId对应Sentinel Dashboard中的定义data-type: jsonrule-type: flow

1.2、ReadableDataSource

  客户端还需要一个读数据源,负责监听配置文件的变化,并将Nacos的配置文件变更,同步到客户端的内存中,可以通过引入jar包实现:

<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

  在Nacos的sentinel-extensionsentinel-datasource-nacos模块,有一个官方实现好的Nacos读数据源:NacosDataSource,同样地,也可以通过客户端的SPI机制被调用,在1.1的NacosDataSourceInitFuncinit方法中加入:

        ReadableDataSource<String, List<FlowRule>> flowRuleDataSource =new NacosDataSource<>(serverAddr, groupId, dataId, source -> {return JSON.parseObject(source, new TypeReference<List<FlowRule>>() {});});FlowRuleManager.register2Property(flowRuleDataSource.getProperty());

  在NacosDataSource中,构造时会做三件事:

  1. 创建配置监听器,并且实现receiveConfigInfo方法,在配置发生变更时回调。
  2. 初始化配置监听器,将上一步创建的configListenerdataId绑定。
  3. 加载配置,从本地或Nacos配置中心读取配置。

在这里插入图片描述
  initNacosListener:这里最终会调用到ConfigRpcTransportClient#startInternal,也就是监听listenExecutebell队列的标志,然后执行executeConfigListen的逻辑:

  1. 远程获取配置文件。
  2. 对有变化的配置调用对应的监听器去处理。

在这里插入图片描述
在这里插入图片描述

  loadInitialConfig是主动从nacos配置中心拉取配置:
在这里插入图片描述
在这里插入图片描述
  最终使用的是Nacos读取配置的关键api:

configService.getConfig(String dataId, String group, long timeoutMs);

在这里插入图片描述

二、push模式的Sentinel控制台实现

  除了改造客户端,也可以对于Sentinel的控制台源码进行修改,达到同步配置信息的目的。控制台源码修改的思路,是对于接收客户端页面操作的FlowControllerV1类进行修改,首先引入ConfigService ,因为需要用到其中的两个关键api:

    @Autowiredprivate ConfigService configService;

  在新增规则时,原本会调用FlowControllerV1apiAddFlowRule方法,推送配置信息到客户端
在这里插入图片描述
  可以修改这一部分的代码,直接将配置推送到Nacos配置中心,而不必再经过客户端
在这里插入图片描述
  获取规则也是同样的道理,直接改造成从Nacos配置中心获取:
在这里插入图片描述
在这里插入图片描述
  改服务端源码的方式,比修改客户端代码更加简便,流程上也更加清晰,无需经过第三方去操作Nacos配置中心,而是直接在服务端就对配置中心进行操作。
  其中NacosConfigUtil是自定义的:

public final class NacosConfigUtil {public static final String GROUP_ID = "SENTINEL_GROUP";public static final String FLOW_DATA_ID_POSTFIX = "-flow-rules";public static final String PARAM_FLOW_DATA_ID_POSTFIX = "-param-flow-rules";public static final String DEGRADE_DATA_ID_POSTFIX = "-degrade-rules";public static final String SYSTEM_DATA_ID_POSTFIX = "-system-rules";public static final String AUTHORITY_DATA_ID_POSTFIX = "-authority-rules";public static final String GATEWAY_FLOW_DATA_ID_POSTFIX = "-gateway-flow-rules";public static final String GATEWAY_API_DATA_ID_POSTFIX = "-gateway-api-rules";public static final String CLUSTER_MAP_DATA_ID_POSTFIX = "-cluster-map";/*** cc for `cluster-client`*/public static final String CLIENT_CONFIG_DATA_ID_POSTFIX = "-cc-config";/*** cs for `cluster-server`*/public static final String SERVER_TRANSPORT_CONFIG_DATA_ID_POSTFIX = "-cs-transport-config";public static final String SERVER_FLOW_CONFIG_DATA_ID_POSTFIX = "-cs-flow-config";public static final String SERVER_NAMESPACE_SET_DATA_ID_POSTFIX = "-cs-namespace-set";//超时时间public static final int READ_TIMEOUT = 3000;private NacosConfigUtil() {}/*** RuleEntity----->Rule* @param entities* @return*/public static String convertToRule(List<? extends RuleEntity> entities){return JSON.toJSONString(entities.stream().map(r -> r.toRule()).collect(Collectors.toList()));}/*** ApiDefinitionEntity----->ApiDefinition* @param entities* @return*/public static String convertToApiDefinition(List<? extends ApiDefinitionEntity> entities){return JSON.toJSONString(entities.stream().map(r -> r.toApiDefinition()).collect(Collectors.toList()));}/*** GatewayFlowRuleEntity----->GatewayFlowRule* @param entities* @return*/public static String convertToGatewayFlowRule(List<? extends GatewayFlowRuleEntity> entities){return JSON.toJSONString(entities.stream().map(r -> r.toGatewayFlowRule()).collect(Collectors.toList()));}}

三、规则转换失效的解决

  所有的规则实体,都实现了一个共同的父类RuleEntity
在这里插入图片描述  如果只是在推送规则或获取规则时,将String转成List或将List转成String,例如客户端加入的NacosWritableDataSource
在这里插入图片描述
  会存在问题,因为每一个RuleEntity子类实现,层级结构不一定是一样的:
在这里插入图片描述


  实际上在服务端,每次操作都是经过类型转换的:
在这里插入图片描述
服务端同步规则到客户端
在这里插入图片描述
服务端从客户端拉取配置


  如果是在服务端进行的改造,只需要在FlowControllerV1中,对于发布规则和拉取规则,进行实体转换即可:
在这里插入图片描述
在这里插入图片描述
服务端发布规则到配置中心

在这里插入图片描述
服务端从配置中心拉取规则

总结:Sentinel规则持久化的Push模式实现方案

在基于 Nacos 的 Sentinel 规则持久化中,Push 模式主要有两种实现思路,分别是基于微服务端和基于Sentinel控制台服务端的实现方式:

1. 微服务端实现(基于客户端读写数据源)

  • 读数据源改造
    微服务端通过引入 sentinel-datasource-nacos 组件,使用 ConfigService.getConfig API 从 Nacos 配置中心同步读取规则,完成规则的动态感知与内存同步。
  • 写数据源改造
    微服务端需自行实现 WritableDataSource 接口(例如通过 SPI 或直接注入 Spring 容器),在规则变更时调用 ConfigService.publishConfig API 将规则推送至 Nacos,确保规则持久化和分发。

2. Sentinel控制台服务端实现(基于控制台读写)

  • FlowControllerV1 中的接口进行改造,包括:
    • 查询规则:apiQueryMachineRules
    • 新增规则:apiAddFlowRule
    • 修改规则:apiUpdateFlowRule
    • 删除规则:apiDeleteFlowRule
  • 在规则操作时,直接通过 Nacos 的 ConfigService.getConfigConfigService.publishConfig 完成规则的读取与持久化,不再依赖客户端推送,从而简化了规则同步的流程。

流程对比

微服务端模式:

  • Sentinel控制台触发规则变更 → 将规则推送至微服务端 → 微服务端通过写数据源将规则持久化到内存并同步推送到 Nacos 配置中心。
  • Sentinel控制台读取规则 → 微服务端通过读数据源从 Nacos 获取规则 → 更新本地缓存 → 返回规则给控制台。

Sentinel控制台服务端模式:

  • Sentinel控制台触发规则变更 → 直接将变更同步至 Nacos 配置中心 → 微服务端监听 Nacos 配置中心的变更事件,动态更新本地规则内存。
  • Sentinel控制台读取规则 → 直接从 Nacos 配置中心拉取规则,同时在本地进行缓存。

方案对比总结

  • 基于控制台服务端的实现方式更加简单清晰,避免了客户端冗余处理逻辑。
  • 配置同步链路缩短,易于排查问题,且可以充分利用配置中心的高可用能力。
  • 对于规则格式转换、兼容性问题的处理也更为集中和统一,降低了微服务端的复杂度。
场景动作关键点
配置中心 → 应用端JSON字符串 → Java对象需要 反序列化
应用端 → 配置中心Java对象 → JSON字符串需要 序列化
规则功能类型规则对象类实体封装类(控制台用)说明
流控规则(Flow Rule)FlowRuleFlowRuleEntity控制QPS或并发量的流量限制
熔断降级规则(Degrade Rule)DegradeRuleDegradeRuleEntity根据异常比例、RT或异常数来熔断
系统保护规则(System Rule)SystemRuleSystemRuleEntity控制总体 Load、CPU 使用率等
授权规则(Authority Rule)AuthorityRuleAuthorityRuleEntity控制资源访问黑白名单
热点参数限流规则(ParamFlow Rule)ParamFlowRuleParamFlowRuleEntity对某些参数的访问频率进行限流
网关流控规则(Gateway Flow Rule)GatewayFlowRuleGatewayFlowRuleEntitySentinel网关限流规则(用于Spring Cloud Gateway / Zuul)
网关API分组规则(Gateway API Definition)ApiDefinitionGatewayApiDefinitionEntity网关端自定义API分组

相关文章:

  • 数据结构和算法(九)--红黑树
  • Windows11系统中GIT下载
  • 【2025最新面试八股常问知识点】HTTP1.0,HTTP1.1,HTTP2.0,HTTP3.0,HTTP的进化之路。
  • TI---sysconfig生成宏
  • PyQt6实例_消息工具_使用与完整代码分享
  • 牛客:BM1 反转链表
  • 4.26 数据交互升级引入配置文件
  • JBoss Web 安全问题实战总结(Session / CSP / Host Header)
  • threejs 零基础学习day01
  • Tauri文件系统操作:桌面应用的核心能力(入门系列四)
  • 深入理解N皇后问题:从DFS到对角线优化
  • Linux | Mfgtools 修改单独只烧写 Uboot,内核,文件系统
  • 用python写一个相机选型的简易程序
  • 视觉大模型专栏导航
  • 可视化大屏开发前提了解
  • MySQL 分布式架构与实战:从单机到集群的进阶之路(附生产级架构设计)
  • Spring AI Alibaba - Milvus 初体验,实现知识库效果
  • QT6 源(51)篇一:存储 c 语言字符串的类 QByteArray 的使用举例,采用 ascii 码字符集。函detach()的调用时机,
  • 【SSH 端口转发】通过SSH端口转发实现访问远程服务器的 tensorboard
  • 学习笔记——《Java面向对象程序设计》-内部类、匿名类、异常类
  • 起底网红热敷贴“苗古金贴”:“传承人”系AI生成,“千年秘方”实为贴牌货
  • 新希望去年归母净利润4.74亿同比增逾九成,营收降27%
  • 深圳大学传播学院院长巢乃鹏已任深圳大学副校长
  • 美官员称与乌克兰会谈富有成效,但仍存重大分歧
  • 神二十成功对接空间站
  • 全品系停货?泸州老窖:暂未接到通知,常规调控手段