Sentinel,中文翻譯爲哨兵,是爲微服務提供流量控制、熔斷降級的功能,它和Hystrix提供的功能同樣,能夠有效的解決微服務調用產生的「雪崩」效應,爲微服務系統提供了穩定性的解決方案。隨着Hytrxi進入了維護期,再也不提供新功能,Sentinel是一個不錯的替代方案。一般狀況,Hystrix採用線程池對服務的調用進行隔離,Sentinel才用了用戶線程對接口進行隔離,兩者相比,Hystrxi是服務級別的隔離,Sentinel提供了接口級別的隔離,Sentinel隔離級別更加精細,另外Sentinel直接使用用戶線程進行限制,相比Hystrix的線程池隔離,減小了線程切換的開銷。另外Sentinel的DashBoard提供了在線更改限流規則的配置,也更加的優化。html
從官方文檔的介紹,Sentinel 具備如下特徵:java
Sentinel dashboard提供一個輕量級的控制檯,它提供機器發現、單機資源實時監控、集羣資源彙總,以及規則管理的功能。您只須要對應用進行簡單的配置,就可使用這些功能。git
注意: 集羣資源彙總僅支持 500 臺如下的應用集羣,有大概 1 - 2 秒的延時。github
下載最新的sentinel dashboard,下載地址爲github.com/alibaba/Sen…spring
下載完啓動,啓動端口爲8748,啓動命令以下:api
java -Dserver.port=8748 -Dcsp.sentinel.dashboard.server=localhost:8748 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.1.jar
複製代碼
本次教程的例子在上一節的例子的基礎上進行改造。瀏覽器
在consumer的pom文件加上spring cloud sentinel的依賴,以下:markdown
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
複製代碼
配置文件application.yml加上以下的配置:app
server:
port: 8763
spring:
application:
name: consumer
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
sentinel:
transport:
port: 18763
dashboard: localhost:8748
feign:
sentinel:
enabled: true
複製代碼
經過feign.sentinel.enable開啓Feign和sentinel的自動適配。配置sentinel的dashboard的地址。框架
經過這樣簡單的配置,Feign和sentinel就配置好了。再啓動三個工程provider\consumer\gateway。
在瀏覽器上屢次訪問http://localhost:5000/consumer/hi-feign
在瀏覽器上訪問localhost:8748,登錄sentinel的控制檯,登錄用戶爲sentinel,密碼爲sentinel。
consumer服務的/hi-feign接口,增長一個流控規則:
qps爲1,快速訪問http://localhost:5000/consumer/hi-feign,會有失敗的狀況。
Spring cloud gateway已經適配了sentinel,在gatewayg工程的pom文件加上相關依賴:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
複製代碼
在配置文件application.yml上加上sentinel dashboard的配置:
spring:
cloud:
sentinel:
transport:
port: 15000
dashboard: localhost:8748
複製代碼
建立一個網關分組和網關的限流規則,代碼以下,參考github.com/alibaba/Sen…
@Configuration
public class GatewayConfiguration {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the block exception handler for Spring Cloud Gateway.
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
@Bean
@Order(-1)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
@PostConstruct
public void doInit() {
initCustomizedApis();
initGatewayRules();
}
private void initCustomizedApis() {
Set<ApiDefinition> definitions = new HashSet<>();
ApiDefinition api1 = new ApiDefinition("consumer")
.setPredicateItems(new HashSet<ApiPredicateItem>() {{
add(new ApiPathPredicateItem().setPattern("/consumer/**")
.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
ApiDefinition api2 = new ApiDefinition("provider")
.setPredicateItems(new HashSet<ApiPredicateItem>() {{
add(new ApiPathPredicateItem().setPattern("/provider/**")
.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
definitions.add(api1);
definitions.add(api2);
GatewayApiDefinitionManager.loadApiDefinitions(definitions);
}
private void initGatewayRules() {
Set<GatewayFlowRule> rules = new HashSet<>();
rules.add(new GatewayFlowRule("consumer")
.setCount(10)
.setIntervalSec(1)
);
rules.add(new GatewayFlowRule("consumer")
.setCount(2)
.setIntervalSec(2)
.setBurst(2)
.setParamItem(new GatewayParamFlowItem()
.setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_CLIENT_IP)
)
);
rules.add(new GatewayFlowRule("provider")
.setCount(10)
.setIntervalSec(1)
.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)
.setMaxQueueingTimeoutMs(600)
.setParamItem(new GatewayParamFlowItem()
.setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_HEADER)
.setFieldName("X-Sentinel-Flag")
)
);
rules.add(new GatewayFlowRule("provider")
.setCount(1)
.setIntervalSec(1)
.setParamItem(new GatewayParamFlowItem()
.setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM)
.setFieldName("pa")
)
);
rules.add(new GatewayFlowRule("provider")
.setCount(2)
.setIntervalSec(30)
.setParamItem(new GatewayParamFlowItem()
.setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM)
.setFieldName("type")
.setPattern("warn")
.setMatchStrategy(SentinelGatewayConstants.PARAM_MATCH_STRATEGY_CONTAINS)
)
);
rules.add(new GatewayFlowRule("provider")
.setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME)
.setCount(5)
.setIntervalSec(1)
.setParamItem(new GatewayParamFlowItem()
.setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM)
.setFieldName("pn")
)
);
GatewayRuleManager.loadRules(rules);
}
}
複製代碼
在sentinel 控制檯爲gateway建立一個限流規則,以下:
流控規則爲qps=1,快速訪問http://localhost:5000/consumer/hi-feign,在qps>1的狀況下,會報如下的錯誤:
Blocked by Sentinel: FlowException
複製代碼
可見sentinel的配置已經生效,更多sentinel教程,請關注fangzhipeng.com網站。
www.fangzhipeng.com/springcloud…