一、Sentinel 描叙
1、Sentinel作用
Sentinel,中文翻譯為哨兵,是為微服務提供流量控制、熔斷降級的功能,它和Hystrix提供的功能一樣,可以有效的解決微服務調用産生的“雪崩”效應,為微服務系統提供了穩定性的解決方案。随着Hytrxi進入了維護期,不再提供新功能,Sentinel是一個不錯的替代方案。通常情況,Hystrix采用線程池對服務的調用進行隔離,Sentinel才用了使用者線程對接口進行隔離,二者相比,Hystrxi是服務級别的隔離,Sentinel提供了接口級别的隔離,Sentinel隔離級别更加精細,另外Sentinel直接使用使用者線程進行限制,相比Hystrix的線程池隔離,減少了線程切換的開銷。另外Sentinel的DashBoard提供了線上更改限流規則的配置,也更加的優化。
2、Sentinel 具有以下特征
從官方文檔的介紹,Sentinel 具有以下特征:
豐富的應用場景: Sentinel 承接了阿裡巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的範圍)、消息削峰填谷、實時熔斷下遊不可用應用等。
完備的實時監控: Sentinel 同時提供實時的監控功能。您可以在控制台中看到接入應用的單台機器秒級資料,甚至 500 台以下規模的叢集的彙總運作情況。
廣泛的開源生态: Sentinel 提供開箱即用的與其它開源架構/庫的整合子產品,例如與 Spring Cloud、Dubbo、gRPC 的整合。您隻需要引入相應的依賴并進行簡單的配置即可快速地接入 Sentinel。
完善的 SPI 擴充點: Sentinel 提供簡單易用、完善的 SPI 擴充點。您可以通過實作擴充點,快速的定制邏輯。例如定制規則管理、适配資料源等。
3、如何在Spring Cloud中使用Sentinel
Sentinel的使用分為兩部分:
sentinel-dashboard:與hystrix-dashboard類似,但是它更為強大一些。除了與hystrix-dashboard一樣提供實時監控之外,還提供了流控規則、熔斷規則的線上維護等功能。
用戶端整合:每個微服務用戶端都需要整合sentinel的用戶端封裝與配置,才能将監控資訊上報給dashboard展示以及實時的更改限流或熔斷規則等。
4、Sentinel 和 hytrix的差別
二、Sentinel 控制台 Sentinel DashBoard
Sentinel DashBoard
Sentinel 控制台提供一個輕量級的控制台,它提供機器發現、單機資源實時監控、叢集資源彙總,以及規則管理的功能.
1、下載下傳
Sentinel DashBoard下載下傳位址:https://github.com/alibaba/Sentinel/releases
下載下傳 jar 檔案即可
2、啟動
下載下傳完成後,以以下的指令啟動
java -jar sentinel-dashboard-1.6.1.jar
啟動端口為8080,啟動修改端口添加指令 -Dserver.port=8081
3、通路
通路:http://localhost:8080
預設賬号密碼:sentinel / sentinel
登入成功展示如下,預設沒有任何内容的
其他啟動指定:
-Dsentinel.dashboard.auth.username=sentinel: 用于指定控制台的登入使用者名為 sentinel;
-Dsentinel.dashboard.auth.password=123456: 用于指定控制台的登入密碼為 123456;如果省略這兩個參數,預設使用者和密碼均為 sentinel
-Dserver.servlet.session.timeout=7200: 用于指定 Spring Boot 服務端 session 的過期時間,如 7200 表示 7200 秒;60m 表示 60 分鐘,預設為 30 分鐘;
三、springboot 整合 Sentinel
Sentinel 有兩種配置方式
1、使用代碼+注解配置(看7)
2、使用控制台配置(看6)
3.1、pom.xml 依賴
<!-- sentinel -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>0.9.0.RELEASE</version>
</dependency>
3.2、application.yml
- 在工程的配置檔案application.yml檔案中配置,需要新增2個配置:
- spring.cloud.sentinel.transport.port: 8719 ,這個端口配置會在應用對應的機器上啟動一個 Http Server,該 Server 會與 Sentinel 控制台做互動。比如 Sentinel 控制台添加了1個限流規則,會把規則資料 push 給這個 Http Server 接收,Http Server 再将規則注冊到 Sentinel 中。
- spring.cloud.sentinel.transport.dashboard: 8080,這個是Sentinel DashBoard的位址。
## 在工程的配置檔案application.yml檔案中配置,需要新增2個配置:
## spring.cloud.sentinel.transport.port: 8719 ,這個端口配置會在應用對應的機器上啟動一個 Http Server,該 Server 會與 Sentinel 控制台做互動。比如 Sentinel 控制台添加了1個限流規則,會把規則資料 push 給這個 Http Server 接收,Http Server 再将規則注冊到 Sentinel 中。
## spring.cloud.sentinel.transport.dashboard: 8080,這個是Sentinel DashBoard的位址。
server:
port: 8090
spring:
application:
name: alibaba-alibaba-sentinel
cloud:
nacos:
discovery:
server-addr: 192.168.177.128:8848
###
sentinel:
transport:
### 目前項目Http Server ip,主要主要是和Sentinel 的DashBoard控制台系統進行通訊
port: 8719
### Sentinel 控制台DashBoard的位址
dashboard: http://localhost:8080
3.4、測試接口1(指定方法,不介意,代碼都在一個地方)
關于@SentinelResource注解最主要的兩個用法:限流控制和熔斷降級的具體使用案例介紹完了。另外,該注解還有一些其他更精細化的配置,比如忽略某些異常的配置、預設降級函數等等
package com.example.alibabasentinel.service;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* TODO 服務熔斷/限流/降級(指定方法)
* @author 王松
* @mail [email protected]
* @date 2020/1/22 0022 20:35
*/
@RestController
public class TestService1Impl {
/**
* TODO 測試方法(目前類處理-服務降級)
* getName :限流名稱,控制台添加一定要選擇該值,勿添加為 /getName 預設名,否則exceptionHandler 參數無效
* exceptionHandler : 服務限流降級後執行的方法
*/
@GetMapping("/getName")
@SentinelResource(value = "getName", blockHandler = "exceptionHandler")
public String getName() {
return "wangsong";
}
/**
* TODO 處理限流與阻塞(服務降級傳回友好提示),方法名對應 blockHandler的參數,服務限流降級後執行的方法
*
*/
public String exceptionHandler(BlockException ex) {
System.out.println("====" + ex);
return "目前通路人數過多,請稍後再試";
}
}
參考傳回值:
1、目前通路人數過多,請稍後再試
2、正在排隊中…
3.5、測試接口2(指定Handler類的方法)
添加測試方法
package com.example.alibabasentinel.service;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.example.alibabasentinel.handler.MyBlockHandlerClass;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* TODO 服務熔斷/限流/降級(指定Handler類的方法)
* @author 王松
* @mail [email protected]
* @date 2020/1/22 0022 20:40
*/
@RestController
public class TestService2Impl {
/**
* TODO 測試方法(指定Handler類處理-服務降級),blockHandlerClass = MyBlockHandlerClass.class
* getName :限流名稱,控制台添加一定要選擇該值,勿添加為 /getName2 預設名,否則exceptionHandler 參數無效
* blockHandlerClass :服務限流/異常等指定類執行降級方法
* blockHandler: 服務限流執行的降級方法
* fallback : 服務異常執行的降級方法
*/
@GetMapping("/getName2")
@SentinelResource(value = "getName2", blockHandlerClass = MyBlockHandlerClass.class, blockHandler = "blockHandlerFunc", fallback = "fallbackFunc")
public String getName2(String a) {
return "wangsong2";
}
}
添加 MyBlockHandlerClass 類 處理服務熔斷降級
import com.alibaba.csp.sentinel.slots.block.BlockException;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class MyBlockHandlerClass {
// 處理限流與阻塞(服務降級傳回友好提示)
public static String blockHandlerFunc(String a, BlockException e){
log.warn("限流了==="+a,e);
return "目前通路人數過多,請稍後再試";
}
// 服務異常(降級處理)
public static String fallbackFunc(String a){
log.warn("異常==="+a);
return "";
}
}
3.6、控制台添加流控并測試
qbs:門檻值 = 每秒能調用該接口多少次
線程數:門檻值 = 請求最多有多少個線程池來處理(預設1)
項目啟動後等一下下,控制台在會出現目前服務資訊
先通路接口 /getName 幾次,控制台才會出現該接口資訊,
3.6.1、添加流控(接口到達門檻值自動熔斷)
getName = @SentinelResource注解的value 值,如果流控添加到 /getName ,将無法使用服務降級功能
添加流控qbs,設定門檻值為2
qbs:門檻值 = 每秒能調用該接口多少次
線程數:門檻值 = 請求最多有多少個線程池來處理(預設1)
3.6.2、通路接口(服務降級)
正常通路接口傳回響應資料,如目前:wangsong
到達門檻值上限 ,傳回:Blocked by Sentinel (flow limiting)
設定 blockHandle, 到達門檻值上限,傳回如下:
如:@SentinelResource(value=“getName”, blockHandler = “exceptionHandler”),
四、@SentinelResource 注解說明
注解key | 支援版本 | 注解value 說明 |
---|---|---|
value | 資源名稱,必需項(不能為空) | |
entryType | entry 類型,可選項(預設為 EntryType.OUT) | |
blockHandler / blockHandlerClass | blockHandler對應處理 BlockException 的函數名稱,可選項。blockHandler 函數通路範圍需要是public,傳回類型需要與原方法相比對,參數類型需要和原方法相比對并且最後加一個額外的參數,類型為 BlockException。blockHandler 函數預設需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定 blockHandlerClass 為對應的類的 Class 對象,注意對應的函數必需為 static 函數,否則無法解析 | |
fallback | fallback 函數名稱,可選項,用于在抛出異常的時候提供 fallback 處理邏輯。fallback 函數可以針對所有類型的異常(除了exceptionsToIgnore裡面排除掉的異常類型)進行處理。fallback 函數簽名和位置要求: 傳回值類型必須與原函數傳回值類型一緻; 方法參數清單需要和原函數一緻,或者可以額外多一個 Throwable 類型的參數用于接收對應的異常。fallback 函數預設需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定 fallbackClass 為對應的類的 Class 對象,注意對應的函數必需為 static 函數,否則無法解析。 | |
defaultFallback | since 1.6.0 | :預設的 fallback 函數名稱,可選項,通常用于通用的 fallback 邏輯(即可以用于很多服務或方法)。預設 fallback 函數可以針對所有類型的異常(除了exceptionsToIgnore裡面排除掉的異常類型)進行處理。若同時配置了 fallback 和 defaultFallback,則隻有 fallback 會生效。defaultFallback 函數簽名要求:傳回值類型必須與原函數傳回值類型一緻; 方法參數清單需要為空,或者可以額外多一個 Throwable 類型的參數用于接收對應的異常。 |
defaultFallback | 函數預設需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定 fallbackClass 為對應的類的 Class 對象,注意對應的函數必需為 static 函數,否則無法解析。 | |
exceptionsToIgnore | since 1.6.0 | 用于指定哪些異常被排除掉,不會計入異常統計中,也不會進入 fallback 邏輯中,而是會原樣抛出。 |
五、java 代碼手動添加流控配置
pom 依賴,yml配置,看 3.1, 3.2
定義限流的接口添加注解看 3.4, 3.5
測試看 3.6
// 流控接口
private static final String GETORDER_KEY = "getOrder";
// 調用接口方式添加流控
@RequestMapping("/initFlowQpsRule")
public String initFlowQpsRule() {
List<FlowRule> rules = new ArrayList<FlowRule>();
FlowRule rule1 = new FlowRule();
rule1.setResource(GETORDER_KEY);
// 設定QPS控制在2以内
rule1.setCount(1);
// 限流規則QPS
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule1.setLimitApp("default");
rules.add(rule1);
// 添加流控集
FlowRuleManager.loadRules(rules);
return "....限流配置初始化成功..";
}
六、Sentinel 資料持久化
1、pom.xml 依賴添加sentinel-datasource-nacos
<!-- sentinel ,可需啟動dashboard 檢視配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>0.9.0.RELEASE</version>
</dependency>
<!-- sentinel 資料持久化到nacos -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.5.2</version>
</dependency>
2、nacos 添加 sentinel 配置
建立服務對應的 sentinel 配置檔案,使用 json
選擇json,添加資料
[
{
"resource": "/hello",
"limitApp": "default",
"grade": 1,
"count": 5,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
- resource:資源名,即限流規則的作用對象
- limitApp:流控針對的調用來源,若為 default 則不區分調用來源
- grade:限流門檻值類型(QPS 或并發線程數);0代表根據并發數量來限流,1代表根據QPS來進行流量控制
- count:限流門檻值
- strategy:調用關系限流政策
- controlBehavior:流量控制效果(直接拒絕、Warm Up、勻速排隊)
-
clusterMode:是否為叢集模式
這裡我們隻做簡單的配置解釋,以便于了解這裡的配置作用。實際上這裡還有非常多可配置選項和規則,更複雜的配置後面我們單獨開一篇來深入學習。
3、application.yml 完整配置
# 在工程的配置檔案application.yml檔案中配置,需要新增2個配置:
# spring.cloud.sentinel.transport.port: 8719 ,這個端口配置會在應用對應的機器上啟動一個 Http Server,該 Server 會與 Sentinel 控制台做互動。比如 Sentinel 控制台添加了1個限流規則,會把規則資料 push 給這個 Http Server 接收,Http Server 再将規則注冊到 Sentinel 中。
# spring.cloud.sentinel.transport.dashboard: 8080,這個是Sentinel DashBoard的位址。
server:
port: 8090
spring:
application:
name: spring-cloud-alibaba-sentinel
cloud:
### nacos 注冊中心
nacos:
discovery:
server-addr: 192.168.177.132:8848
sentinel:
### 和 Sentinel控制台DashBoard通訊,|| port:目前項目Http Server ip位址,|| dashboard:Sentinel 控制台DashBoard的位址
transport:
port: 8719
dashboard: http://localhost:8080
### 配置資料源,支援file本地,nacos,zk,阿波羅,配置資料庫0,讀取 nacos 配置資料
datasource:
ds0:
nacos:
server-addr: 192.168.177.132:8848
dataId: spring-cloud-alibaba-sentinel.json
groupId: DEFAULT_GROUP
rule-type: flow
### 檔案類型
data-type: json
sentinel 部分
spring:
cloud:
sentinel:
transport:
port: 8719
dashboard: http://localhost:8080
datasource:
ds0:
nacos:
server-addr: 192.168.177.132:8848
dataId: spring-cloud-alibaba-sentinel.json
groupId: DEFAULT_GROUP
rule-type: flow
data-type: json
4、檢視是否配置成功
啟動項目發現啟動日志: [Sentinel Starter] DataSource ds0-sentinel-nacos-datasource load 1 FlowRule
表示配置成功了
進入Sentinel 控制台–> 流控規則,發現已經存在配置規則了,配置成功
- 1、如是重新啟動項目, 通路任意接口在等待幾秒重新整理
- 2、配置了nacos 盡量從來nacos 添加和修改規則,Sentinel 控制台修改的下次重新啟動項目将失效
七、gateway 整合 Sentinel 實作服務限流
1、添加sentinel 限流核心配置
package com.gateway.sentinel;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;
import java.util.Collections;
import java.util.List;
/**
* TODO sentinel 限流核心配置
* @author ws
* @mail [email protected]
* @date 2020/2/17 0017 14:08
*/
@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(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
}
2、添加sentinel 限流規則
此配置可以配置到nacos,動态配置限流規則
package com.gateway.sentinel;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.Set;
/**
* TODO 限流規則配置
*
* @author ws
* @mail [email protected]
* @date 2020/2/17 0017 14:09
*/
@Slf4j
@Component
public class SentinelApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
initGatewayRules();
}
/**
* 配置限流規則
*/
private void initGatewayRules() {
Set<GatewayFlowRule> rules = new HashSet<>();
rules.add(new GatewayFlowRule("test")
// 限流門檻值
.setCount(1)
// 統計時間視窗,機關是秒,預設是 1 秒
.setIntervalSec(1)
);
GatewayRuleManager.loadRules(rules);
}
}
3、配置自定義傳回資訊(如果配置了全局異常看四)
package com.gateway.sentinel;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebExceptionHandler;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
* TODO 限流錯誤傳回資訊
* @author ws
* @mail [email protected]
* @date 2020/2/17 0017 14:13
*/
public class JsonSentinelGatewayBlockExceptionHandler implements WebExceptionHandler {
public JsonSentinelGatewayBlockExceptionHandler(List<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
}
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
ServerHttpResponse serverHttpResponse = exchange.getResponse();
serverHttpResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
byte[] datas = "{\"code\":403,\"msg\":\"API接口被限流\"}".getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = serverHttpResponse.bufferFactory().wrap(datas);
return serverHttpResponse.writeWith(Mono.just(buffer));
}
}
4、全局異常傳回自定義資訊
全局異常配置暫不做說明
本文參考文章1:https://blog.csdn.net/u013184307/article/details/95973022
本文參考文章2:https://blog.csdn.net/a772304419/article/details/99689562
資料持久化參考:http://blog.didispace.com/spring-cloud-alibaba-sentinel-2-1/
創作不易感謝大家的觀看!