How to Dynamically Manage Sentinel Rules with File-Based DataSource in Spring Cloud
This guide explains how to configure Alibaba Sentinel to load flow‑control, degradation, and system rules from files using a custom AutoRefreshDataSource in a Spring Cloud Alibaba project, covering API methods, pull/push data source modes, Maven setup, YAML settings, rule JSON examples, and Java implementation details.
Sentinel's default console‑configured rules are stored in memory and disappear when the client disconnects.
Sentinel's design lets developers focus on resource definitions and add flow‑control or degradation rules dynamically. Two ways to modify rules are provided: via API (loadRules) or via DataSource adapters.
Modify rules directly through API (loadRules)
Modify rules by adapting different data sources
Manual API modification is straightforward for testing, but production typically uses dynamic rule sources.
FlowRuleManager.loadRules(List<FlowRule> rules); // modify flow‑control rules
DegradeRuleManager.loadRules(List<DegradeRule> rules); // modify degradation rulesWhen rules are set through the Sentinel console, they are pushed to a unified rule center, and the client listens to real‑time changes via the ReadableDataSource interface.
DataSource extensions commonly use two modes:
Pull mode : the client periodically polls a rule center (e.g., RDBMS, file, VCS) to fetch rules; simple but not real‑time.
Push mode : the rule center pushes updates, and the client registers listeners (e.g., Nacos, Zookeeper) for immediate consistency.
Supported data sources are:
Pull‑based: dynamic file data source, Consul, Eureka
Push‑based: ZooKeeper, Redis, Nacos, Apollo, etcd
Below is a Maven pom.xml configuration for a Spring Cloud Alibaba Sentinel project:
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR1</spring-cloud.version>
<spring-cloud-alibaba-dependencies.version>0.9.0.RELEASE</spring-cloud-alibaba-dependencies.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.12</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>The corresponding application.yml sets server port, application name, management endpoints, and Sentinel properties:
server:
port: 9400
---
spring:
application:
name: my-app
---
management:
endpoints:
web:
exposure:
include: '*'
---
spring:
cloud:
sentinel:
eager: true # disable lazy loading
filter:
enabled: true # enable/disable Spring MVC endpoint protection
transport:
port: 8730
dashboard: localhost:8080 # Sentinel console address
heartbeatIntervalMs: 3000
clientIp: 10.100.102.109Three rule JSON files are placed under src/main/resources:
DegradeRule.json
[
{
"resource": "abc0",
"count": 20.0,
"grade": 0,
"passCount": 0,
"timeWindow": 10
},
{
"resource": "abc1",
"count": 15.0,
"grade": 0,
"passCount": 0,
"timeWindow": 10
}
]FlowRule.json
[
{
"resource": "abc",
"controlBehavior": 0,
"count": 20.0,
"grade": 1,
"limitApp": "default",
"strategy": 0
},
{
"resource": "abc1",
"controlBehavior": 0,
"count": 20.0,
"grade": 1,
"limitApp": "default",
"strategy": 0
}
]SystemRule.json
[
{
"avgRt": 10,
"highestSystemLoad": 5.0,
"maxThread": 10,
"qps": 20.0
}
]A custom data source extending AutoRefreshDataSource reads the rule files and refreshes them when modified:
public class FileRefreshableDataSource<T> extends AutoRefreshDataSource<String, T> {
private static final int MAX_SIZE = 1024 * 1024 * 4;
private static final long DEFAULT_REFRESH_MS = 3000;
private static final int DEFAULT_BUF_SIZE = 1024 * 1024;
private static final Charset DEFAULT_CHAR_SET = Charset.forName("utf-8");
private byte[] buf;
private final Charset charset;
private final File file;
private long lastModified = 0L;
public FileRefreshableDataSource(File file, Converter<String, T> configParser) throws FileNotFoundException {
this(file, configParser, DEFAULT_REFRESH_MS, DEFAULT_BUF_SIZE, DEFAULT_CHAR_SET);
}
// other constructors omitted for brevity
private void firstLoad() {
try {
T newValue = loadConfig();
getProperty().updateValue(newValue);
} catch (Throwable e) {
RecordLog.info("loadConfig exception", e);
}
}
@Override
public String readSource() throws Exception {
if (!file.exists()) {
RecordLog.warn(String.format("[FileRefreshableDataSource] File does not exist: %s", file.getAbsolutePath()));
}
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(file);
FileChannel channel = inputStream.getChannel();
if (channel.size() > buf.length) {
throw new IllegalStateException(file.getAbsolutePath() + " file size=" + channel.size() + ", is bigger than bufSize=" + buf.length + ". Can't read");
}
int len = inputStream.read(buf);
return new String(buf, 0, len, charset);
} finally {
if (inputStream != null) {
try { inputStream.close(); } catch (Exception ignore) {}
}
}
}
@Override
protected boolean isModified() {
long curLastModified = file.lastModified();
if (curLastModified != this.lastModified) {
this.lastModified = curLastModified;
return true;
}
return false;
}
@Override
public void close() throws Exception {
super.close();
buf = null;
}
}A configuration class registers the three rule data sources with Sentinel managers:
@Configuration
public class PullFileDataSource {
@PostConstruct
public void listenRules() throws Exception {
ClassLoader classLoader = getClass().getClassLoader();
String flowRulePath = URLDecoder.decode(classLoader.getResource("FlowRule.json").getFile(), "UTF-8");
String degradeRulePath = URLDecoder.decode(classLoader.getResource("DegradeRule.json").getFile(), "UTF-8");
String systemRulePath = URLDecoder.decode(classLoader.getResource("SystemRule.json").getFile(), "UTF-8");
FileRefreshableDataSource<List<FlowRule>> flowRuleDataSource = new FileRefreshableDataSource<>(flowRulePath, flowRuleListParser);
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
FileRefreshableDataSource<List<DegradeRule>> degradeRuleDataSource = new FileRefreshableDataSource<>(degradeRulePath, degradeRuleListParser);
DegradeRuleManager.register2Property(degradeRuleDataSource.getProperty());
FileRefreshableDataSource<List<SystemRule>> systemRuleDataSource = new FileRefreshableDataSource<>(systemRulePath, systemRuleListParser);
SystemRuleManager.register2Property(systemRuleDataSource.getProperty());
}
private Converter<String, List<FlowRule>> flowRuleListParser = source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {});
private Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject(source, new TypeReference<List<DegradeRule>>() {});
private Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject(source, new TypeReference<List<SystemRule>>() {});
}After starting the service, the Sentinel console displays the rules defined in the configuration files. Modifying the JSON files updates the console in real time, while changes made directly in the console do not rewrite the local files.
Done!
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
