序
本文主要研究一下如何自定义sentinel的DataSource,这里以jdbc为例。
maven
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sentinel</artifactId>
<version>0.2.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
扩展AutoRefreshDataSource
public class JdbcDataSource<T> extends AutoRefreshDataSource<String, T> {
final String DEFAULT_SQL = "SELECT VALUE from PROPERTIES where APPLICATION=? and PROFILE=? and KEY=?";
final PropertiesResultSetExtractor extractor = new PropertiesResultSetExtractor();
JdbcTemplate jdbc;
String app;
String key;
String profile;
public JdbcDataSource(JdbcTemplate jdbc,String app,String profile,String key,ConfigParser<String, T> configParser, long recommendRefreshMs) {
super(configParser, recommendRefreshMs);
this.jdbc = jdbc;
this.app = app;
this.key = key;
this.profile = profile;
}
@Override
public String readSource() throws Exception {
List<String> data = (List<String>) jdbc.query(DEFAULT_SQL,
new Object[] { app, profile, key }, this.extractor);
if(data.size() > 0){
return data.get(0);
}
return null;
}
class PropertiesResultSetExtractor implements ResultSetExtractor<List<String>> {
@Override
public List<String> extractData(ResultSet rs)
throws SQLException, DataAccessException {
List<String> result = new ArrayList<>(1);
while (rs.next()) {
result.add(rs.getString(1));
}
return result;
}
}
}
- 这里以拉模式为例,因而扩展的是AutoRefreshDataSource
数据结构及初始化数据
CREATE TABLE IF NOT EXISTS PROPERTIES (
KEY VARCHAR(128),
VALUE VARCHAR(4096),
APPLICATION VARCHAR(128),
PROFILE VARCHAR(128),
PRIMARY KEY (`KEY`, `APPLICATION`, `PROFILE`)
);
INSERT INTO PROPERTIES (APPLICATION, PROFILE, KEY, VALUE)
VALUES ('sentinel-demo', 'jdbc', 'flow', '[
{
"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
}
]');
INSERT INTO PROPERTIES (APPLICATION, PROFILE, KEY, VALUE)
VALUES ('sentinel-demo', 'jdbc', 'system', '[
{
"avgRt": 10,
"highestSystemLoad": 5.0,
"maxThread": 10,
"qps": 20.0
}
]');
INSERT INTO PROPERTIES (APPLICATION, PROFILE, KEY, VALUE)
VALUES ('sentinel-demo', 'jdbc', 'degrade', '[
{
"resource": "abc0",
"count": 20.0,
"grade": 0,
"passCount": 0,
"timeWindow": 10
},
{
"resource": "abc1",
"count": 15.0,
"grade": 0,
"passCount": 0,
"timeWindow": 10
}
]');
- 这里仿照spring cloud config server的jdbc存储的schema
自动加载
@Component
public class SentinelJdbcAutoConfig implements CommandLineRunner {
@Value("${spring.application.name}")
String app;
@Autowired
private Environment environment;
@Autowired
JdbcTemplate jdbcTemplate;
int defaultRefreshMs = 10*1000;
@Override
public void run(String... args) throws Exception {
String profile = environment.getActiveProfiles().length > 0 ? environment.getActiveProfiles()[0] : "default";
// data source for FlowRule
DataSource<String, List<FlowRule>> flowRuleDataSource = new JdbcDataSource<List<FlowRule>>(jdbcTemplate,
app,profile,"flow", new JsonFlowRuleListParser(),defaultRefreshMs);
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
// data source for DegradeRule
DataSource<String, List<DegradeRule>> degradeRuleDataSource = new JdbcDataSource<List<DegradeRule>>(jdbcTemplate,
app,profile,"degrade", new JsonDegradeRuleListParser(),defaultRefreshMs);
DegradeRuleManager.register2Property(degradeRuleDataSource.getProperty());
// data source for SystemRule
DataSource<String, List<SystemRule>> systemRuleDataSource = new JdbcDataSource<List<SystemRule>>(jdbcTemplate,
app,profile,"system", new JsonSystemRuleListParser(),defaultRefreshMs);
SystemRuleManager.register2Property(systemRuleDataSource.getProperty());
}
}
- 这里在启动时通过FlowRuleManager.register2Property,注册了flowRule、degradeRule、systemRule三类规则的数据源
验证
启动之后访问http://localhost:8080/actuator/sentinel,可以看到如下规则:
{
"DegradeRules": [
{
"resource": "abc1",
"limitApp": "default",
"count": 15,
"timeWindow": 10,
"grade": 0,
"cut": false,
"passCount": 0
},
{
"resource": "abc0",
"limitApp": "default",
"count": 20,
"timeWindow": 10,
"grade": 0,
"cut": false,
"passCount": 0
}
],
"SystemRules": [
{
"resource": null,
"limitApp": null,
"highestSystemLoad": 5,
"qps": -1,
"avgRt": -1,
"maxThread": -1
},
{
"resource": null,
"limitApp": null,
"highestSystemLoad": -1,
"qps": -1,
"avgRt": 10,
"maxThread": -1
},
{
"resource": null,
"limitApp": null,
"highestSystemLoad": -1,
"qps": -1,
"avgRt": -1,
"maxThread": 10
},
{
"resource": null,
"limitApp": null,
"highestSystemLoad": -1,
"qps": 20,
"avgRt": -1,
"maxThread": -1
}
],
"FlowRules": [
{
"resource": "abc1",
"limitApp": "default",
"grade": 1,
"count": 20,
"strategy": 0,
"refResource": null,
"controlBehavior": 0,
"warmUpPeriodSec": 10,
"maxQueueingTimeMs": 500
},
{
"resource": "abc",
"limitApp": "default",
"grade": 1,
"count": 20,
"strategy": 0,
"refResource": null,
"controlBehavior": 0,
"warmUpPeriodSec": 10,
"maxQueueingTimeMs": 500
}
],
"properties": {
"enabled": true,
"port": "7080",
"dashboard": "localhost:9999",
"filter": {
"order": -2147483648,
"urlPatterns": [
"/*"
]
}
}
}
查看sentinel的dashboard,可以发现dashboard也能识别出应用自定义的规则。
小结
sentinel datasource提供了灵活的扩展机制,可以自定义数据源来满足不同应用的需求。