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

spring cloud sentinel 动态规则配置

Sentinel 允许在运行时根据不同的需求动态调整限流、熔断等规则。通过动态规则扩展,你可以实现:

  • 自动调整:根据业务流量的变化自动调整规则。
  • 外部配置支持:规则可以从数据库、配置中心(如 Nacos、Apollo)或者文件等外部来源加载。
  • 热更新:不需要重启应用,规则就能实时生效。

Sentinel 提供两种方式修改规则:

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

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

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

手动修改规则(硬编码方式)一般仅用于测试和演示,生产上一般通过动态规则源的方式来动态管理规则。

DataSource 扩展

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

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

上述集中数据源扩展方式,sentinel是支持springboot自动装配的,下面以文件和nacos配置中心的形式来进行演示流量控制规则动态配置。

首先添加数据源扩展依赖

<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-extension</artifactId>
</dependency>
文件模式

定义一个规则配置文件FlowRule.json放到resources下

[{"resource": "add","controlBehavior": 0,"count": 3.0,"grade": 1,"limitApp": "default","strategy": 0}
]

一个流量配置规则重要属性如下:

Field说明默认值
resource资源名,资源名是限流规则的作用对象
count限流阈值
grade限流阈值类型,QPS 或线程数模式QPS 模式
limitApp流控针对的调用来源default,代表不区分调用来源
strategy调用关系限流策略:直接、链路、关联根据资源本身(直接)
controlBehavior流控效果(直接拒绝 / 排队等待 / 慢启动模式),不支持按调用关系限流直接拒绝

配置文件配置

spring:cloud:sentinel:transport:port: 8719dashboard: localhost:8080datasource:ds1:file:file: classpath:FlowRule.json #指定规则文件位置data-type: json #指定文件格式rule-type: flow #指定规则类型charset: utf-8 #指定文件编码

sentinel的datasource配置支持是Map<String, DataSourcePropertiesConfiguration>类型,可以支持同时配置多个数据源。不同的数据源有几个共同的配置项:

data-type: 数据格式类型,默认json

rule-type:规则类型,flow,grade,system等值可配置,具体项可查看RuleType枚举类。

converterClass:配置数据格式化处理类,默认json使用的jackson的ObjectMapper进行解析。

Nacos数据源

nacos添加额外依赖

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

配置文件配置

spring:cloud:sentinel:datasource:ds2:nacos:serverAddr: localhost:8848namespace: sentinelgroupId: flowtestdataId: sentinel_system_flow_rule.jsondataType: jsonruleType: flow

nacos数据源配置和其作为配置中心信息差不多,nacos的连接信息,配置资源文件位置。

手动编码配置

除了使用springboot自动装配扩展数据源,也可以通过手动编码的方式进行自定义配置。使用FlowRuleManager.register2Property()方法进行手动注册数据源,例如手动注册一个文件数据源

//读取配置文件内容
ClassLoader classLoader = getClass().getClassLoader();
String flowRulePath = URLDecoder.decode(classLoader.getResource("FlowRule.json").getFile(), "UTF-8");
//定义converter
Converter<String, List<FlowRule>> flowRuleListParser = s -> JSON.parseObject(s,new TypeReference<List<FlowRule>>(){});
//构造FileRefreshableDataSource
FileRefreshableDataSource<List<FlowRule>> flowRuleDataSource = new FileRefreshableDataSource<>(flowRulePath, flowRuleListParser);
//注册数据源
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());

手动注册数据源时候一定要注意代码执行顺序,否则执行过早可能在sentinel的控制台看不到配置规则信息,最好在容器初始化完成后执行,也可以使用sentinel自带的InitFunc的spiloader扩展方式。

动态规则扩展的原理

所有的动态数据源扩展最后都是通过FlowRuleManager.register2Property将数据源注册到规则管理器上。

FlowRuleManager.register2Property()

    public static void register2Property(SentinelProperty<List<FlowRule>> property) {AssertUtil.notNull(property, "property cannot be null");synchronized (LISTENER) {RecordLog.info("[FlowRuleManager] Registering new property to flow rule manager");currentProperty.removeListener(LISTENER);property.addListener(LISTENER);currentProperty = property;}}

这里会给property添加一个listenner。这里以文件类型扩展源来看下。

先来看FileRefreshableDataSource内部动态刷新机制,其实很简单就是一个定时器检测文件变化。FileRefreshableDataSource继承抽象类AutoRefreshDataSource,其构造函数会启动定时器。

AutoRefreshDataSource#startTimerService()

    private void startTimerService() {//初始化线程池service = Executors.newScheduledThreadPool(1,new NamedThreadFactory("sentinel-datasource-auto-refresh-task", true));service.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {try {//文件是否有变化if (!isModified()) {return;}//如果有变化从新从文件读取规则数据T newValue = loadConfig();//调用updateValue方法触发规则更新getProperty().updateValue方法触发规则更新(newValue);} catch (Throwable e) {RecordLog.info("loadConfig exception", e);}}}, recommendRefreshMs, recommendRefreshMs, TimeUnit.MILLISECONDS);}

这里定时周期默认在FileRefreshableDataSource有常量DEFAULT_REFRESH_MS=3000,3秒检测一次。

isModified()在FileRefreshableDataSource实现就是根据文件的修改时间来判断file.lastModified()。

最重要的updateValue()方法,这里的property实例是DynamicSentinelProperty类型,

DynamicSentinelProperty#updateValue()

    public boolean updateValue(T newValue) {if (isEqual(value, newValue)) {return false;}RecordLog.info("[DynamicSentinelProperty] Config will be updated to: {}", newValue);value = newValue;for (PropertyListener<T> listener : listeners) {listener.configUpdate(newValue);}return true;}

这里看到会拿出Property中所有的listener依次调用configUpdate方法。listener的设置在我们第一步注册数据源到FlowRuleManager里就设置了。这里listener的类型是FlowPropertyListener。

FlowRuleManager.FlowPropertyListener.configUpdate()

public synchronized void configUpdate(List<FlowRule> value) {Map<String, List<FlowRule>> rules = FlowRuleUtil.buildFlowRuleMap(value);if (rules != null) {flowRules = rules;}RecordLog.info("[FlowRuleManager] Flow rules received: {}", rules);
}

最后将flowRule更新到内存中。

自动装配数据源原理

在sentinel的自动装配类SentinelAutoConfiguration中会初始化数据源处理类SentinelDataSourceHandler。该handler实现了SmartInitializingSingleton接口,在容器初始化完成后会调用afterSingletonsInstantiated()方法。

SentinelDataSourceHandler#afterSingletonsInstantiated

	public void afterSingletonsInstantiated() {sentinelProperties.getDatasource()//循环处理所有配置的datasource.forEach((dataSourceName, dataSourceProperties) -> {try {List<String> validFields = dataSourceProperties.getValidField();if (validFields.size() != 1) {log.error("[Sentinel Starter] DataSource " + dataSourceName+ " multi datasource active and won't loaded: "+ dataSourceProperties.getValidField());return;}AbstractDataSourceProperties abstractDataSourceProperties = dataSourceProperties.getValidDataSourceProperties();abstractDataSourceProperties.setEnv(env);abstractDataSourceProperties.preCheck(dataSourceName);//将解析验证后数据源信息作为一个bean注册到容器中registerBean(abstractDataSourceProperties, dataSourceName+ "-sentinel-" + validFields.get(0) + "-datasource");}catch (Exception e) {log.error("[Sentinel Starter] DataSource " + dataSourceName+ " build error: " + e.getMessage(), e);}});}

registerBean()方法

	private void registerBean(final AbstractDataSourceProperties dataSourceProperties,String dataSourceName) {BeanDefinitionBuilder builder = parseBeanDefinition(dataSourceProperties, dataSourceName);this.beanFactory.registerBeanDefinition(dataSourceName,builder.getBeanDefinition());// init in SpringAbstractDataSource newDataSource = (AbstractDataSource) this.beanFactory.getBean(dataSourceName);// register property in RuleManagerdataSourceProperties.postRegister(newDataSource);}

dataSourceProperties.postRegister()

	public void postRegister(AbstractDataSource dataSource) {switch (this.getRuleType()) {case FLOW:FlowRuleManager.register2Property(dataSource.getProperty());break;case DEGRADE:DegradeRuleManager.register2Property(dataSource.getProperty());break;...}}

这里看到最后也是通过FlowRuleManager.register2Property()将数据源注册到规则管理器中。

http://www.xdnf.cn/news/1210753.html

相关文章:

  • 【华为机试】20. 有效的括号
  • docker docker、swarm 全流程执行
  • C++多态:面向对象编程的灵魂之
  • 网络安全第15集
  • 力扣30 天 Pandas 挑战(3)---数据操作
  • C# _列表(List<T>)_ 字典(Dictionary<TKey, TValue>)
  • uniapp 实现全局变量
  • Rust 实战三 | HTTP 服务开发及 Web 框架推荐
  • React 中获取当前路由信息
  • 2.oracle保姆级安装教程
  • 《零基础入门AI:传统机器学习入门(从理论到Scikit-Learn实践)》
  • 如何解决人工智能在社会治理中面临的技术和伦理挑战?
  • 网络原理--HTTPHTTPS
  • AI产品经理手册(Ch3-5)AI Product Manager‘s Handbook学习笔记
  • PyCharm插件开发与定制指南:打造个性化开发环境
  • FSMC的配置和应用
  • SpringBoot集成deepseek
  • Export useForm doesn‘t exist in target module
  • vue3组件通信的几种方法,详解
  • 05动手学深度学习(下)
  • Linux - 权限的理解(深入浅出,详细细微)
  • 书籍推荐算法研究
  • gRPC性能陷阱:低延迟网络下的客户端瓶颈揭秘
  • Spark SQL 数组函数合集:array_agg、array_contains、array_sort…详解
  • Zynq SOC FPGA嵌入式裸机设计和开发教程自学笔记:GPIO扩展与中断控制技术,万字详解!!
  • 【变更性别】
  • TCPDump实战手册:协议/端口/IP过滤与组合分析指南
  • ESP32学习-1.第一个程序helloworld
  • 子数组和 问题汇总
  • FPGA实现SRIO高速接口与DSP交互,FPGA+DSP异构方案,提供3套工程源码和技术支持