本文主要研究一下如何自定義sentinel的DataSource,這裏以jdbc爲例。git
<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>
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; } } }
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 } ]');
@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()); } }
啓動以後訪問http://localhost:8080/actuator/sentinel,能夠看到以下規則:github
{ "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也能識別出應用自定義的規則。web
sentinel datasource提供了靈活的擴展機制,能夠自定義數據源來知足不一樣應用的需求。spring