1、環境和資源準備
sentinel支持許多流控方式,比如:單機限流、熔斷降級、集群限流、系統保護規則、黑白名單授權等。
本文介紹如何快速集成使用sentinel,文中以單機限流為例,使用代碼而非控制臺配置的方式限流。
- sentinel官網地址:https://sentinelguard.io/zh-cn/index.html
- Github地址:https://github.com/alibaba/Sentinel
- 本文采用的版本是1.8.0,下載地址:https://github.com/alibaba/Sentinel/releases/tag/v1.8.0
- sentinel-dashboard下載地址:https://github.com/alibaba/Sentinel/releases/download/v1.8.0/sentinel-dashboard-1.8.0.jar
- 本文使用的項目地址:https://github.com/yclxiao/spring-sentinel-demo,代碼中有一部分使用的是官方demo。
2、啟動sentinel-dashboard
從上文地址下載sentinel-dashboard,然后執行命令啟動:JAVA -jar sentinel-dashboard-1.8.0.jar
啟動完畢后,通過http://localhost:8080/#/dashboard訪問dashboard,出現如下界面:
3、項目集成sentinel
項目中集成sentinel分如下5步。
3.1、引入pom
<!-- 這是sentinel的核心依賴 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.0</version>
</dependency>
<!-- 這是將自己項目和sentinel-dashboard打通的依賴 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.0</version>
</dependency>
<!-- 這是使用sentinel對限流資源進行AOP -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.8.0</version>
</dependency>
3.2、增加sentinel-aop
@Configuration
public class AopConfiguration {
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
3.3、增加sentinel.properties配置
在Application.properties同級目錄下,增加sentinel.properties文件,配置內容如下:
# 集成到sentinel的項目名稱
project.name=spring-sentinel-demo
# 對應的sentinel-dashboard地址
csp.sentinel.dashboard.server=localhost:8080
同時需要加載sentinel.properties配置,有兩種加載方式,選擇一種即可,如下:
3.4、設置需要被限流的資源
給需要被限流的資源打上注解@SentinelResource,使用方式如下。
- 默認情況下,超出配置的流控閾值后,直接拋出 FlowException(BlockException) 異常,可以使用blockHandler自定義。
- fallback用于配置熔斷降級的方法,當發生慢調用、異常數、異常比例數,會調用fallback方法。
- 可以針對部分異常情況做忽略處理,不再觸發熔斷降級。
@Service
public class TestServiceImpl implements top.mangod.springsentineldemo.service.TestService {
@Override
@SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {top.mangod.springsentineldemo.service.ExceptionUtil.class})
public void test() {
System.out.println("Test");
}
@Override
@SentinelResource(value = "hello", fallback = "helloFallback")
public String hello(long s) {
if (s < 0) {
throw new IllegalArgumentException("invalid arg");
}
return String.format("Hello at %d", s);
}
@Override
@SentinelResource(value = "helloAnother", defaultFallback = "defaultFallback",
exceptionsToIgnore = {IllegalStateException.class})
public String helloAnother(String name) {
if (name == null || "bad".equals(name)) {
throw new IllegalArgumentException("oops");
}
if ("foo".equals(name)) {
throw new IllegalStateException("oops");
}
return "Hello, " + name;
}
public String helloFallback(long s, Throwable ex) {
// Do some log here.
ex.printStackTrace();
return "Oops, error occurred at " + s;
}
public String defaultFallback() {
System.out.println("Go to default fallback");
return "default_fallback";
}
}
3.5、指定和加載流控規則
文中我使用代碼方式制定流控規則,在控制臺中也可以直接配置流控規則,為什么不使用控制臺方式呢?
如果是類似云原生的部署環境,比如:將spring應用打成Docker鏡像,然后在部署到Kube.NETes中,部署之后Pod地址是會變化。
只要應用的地址變化后,之前的配置就消失了。不可能每次地址變化后都到控制臺去重新配置策略,所以需要選擇代碼方式制定規則。
流控規則一般會有如下幾個:
- 資源限流規則FlowRule
- 異常熔斷降級規則DegradeRule
- 系統過載保護規則SystemRule
- 訪問黑白名單規則AuthorityRule
控制臺設置流控規則,如下:
代碼制定和加載流控規則,如下:
public static void mAIn(String[] args) {
// 加載限流規則
initSentinelRule();
SpringApplication.run(SpringSentinelDemoApplication.class, args);
}
private static void initSentinelRule() {
// 資源限流
FlowRule flowRule = new FlowRule("test")
.setCount(1)
.setGrade(RuleConstant.FLOW_GRADE_QPS);
List<FlowRule> list = new ArrayList<>();
/*if (method) {
FlowRule flowRule1 = new FlowRule("test:sayHello(java.lang.String)")
.setCount(5)
.setGrade(RuleConstant.FLOW_GRADE_QPS);
list.add(flowRule1);
}*/
list.add(flowRule);
FlowRuleManager.loadRules(list);
// 異常降級
/*List<DegradeRule> DegradeRules = new ArrayList<>();
DegradeRule degradeRule = new DegradeRule("");
degradeRule.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType());
degradeRule.setCount(0.7); // Threshold is 70% error ratio
degradeRule.setMinRequestAmount(100)
.setStatIntervalMs(30000) // 30s
.setTimeWindow(10);
DegradeRules.add(degradeRule);
DegradeRuleManager.loadRules(DegradeRules);*/
// 系統負載保護
/*List<SystemRule> systemRules = new ArrayList<>();
SystemRule systemRule = new SystemRule();
systemRule.setHighestSystemLoad(10);
systemRules.add(systemRule);
SystemRuleManager.loadRules(systemRules);*/
// 黑白名單授權訪問
/*AuthorityRule rule = new AuthorityRule();
rule.setResource("test");
rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
rule.setLimitApp("appA,appB");
AuthorityRuleManager.loadRules(Collections.singletonList(rule));*/
}
4、啟動測試
項目啟動完畢后,訪問鏈接http://localhost:9091/foo,就可以在控制臺上看到被限流的資源
在流控規則這里,可以看到上文中在代碼里設置的規則:
啟動項目后,測試限流效果,如下:
- 1秒內多次訪問http://localhost:9091/foo,可以看到觸發了限流異常:
- 輸入http://localhost:9091/foo?t=-1會觸發異常。fallback用于配置熔斷降級的方法,當發生慢調用、異常數、異常比例數時,會調用fallback方法。
- 輸入http://localhost:9091/baz/foo、http://localhost:9091/baz/bad,會分別觸發異常和默認fallback。
5、總結
本文主要介紹spring項目如何快速集成sentinel實現系統限流。
首先啟動sentinel-dashboard,然后使用5個簡單步驟即可使用sentinel限流。
在應用server的IP地址頻繁變動的場景下,建議使用代碼方式限流。
流控的方式較多,你需要根據自身的業務需求做選擇,我一般情況下選擇單機流控和系統保護。