SpringCloud實戰之路 | 應用篇(十)Spring Cloud Alibaba服務哨兵Sentinel
Sentinel介紹
Sentinel是⼀個⾯向雲原⽣微服務的流量控制、熔斷降級組件,可以用來替代Hystrix解決服務雪崩、服務降級、服務熔斷、服務限流等問題。
對比Hystrix來說,Sentinel提供了獨⽴可部署Dashboard控制檯組件,通過在控制檯進行配置即可完成對服務的限流、熔斷、降級等控制,減少了代碼部分的開發
下載地址:https://github.com/alibaba/Sentinel/releases
Sentinel部署
默認端口:8080,有衝突記得修改,這裏改爲了8090
啓動命令:
java -jar sentinel-dashboard-1.7.1.jar --server.port=8090 &
默認⽤戶名/密碼:sentinel/sentinel
訪問:http://localhost:8090/#/dashboard/home
服務整合Sentinel
引入maven依賴
<!--sentinel 核⼼環境 依賴-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
修改yml配置文件
server:
port: 8080
spring:
application:
name: cloud-service-user
main:
allow-bean-definition-overriding: true
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
sentinel:
transport:
dashboard: 127.0.0.1:8090# sentinel dashboard/console 地址
port: 8719
jpa:
database: MySQL
show-sql: true
hibernate:
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl #避免將駝峯命名轉換爲下劃線命名
management:
endpoints:
web:
exposure:
include: "*"
# 暴露健康接口的細節
endpoint:
health:
show-details: always
Sentinel是懶加載的,在完成上述配置後,不會立刻發生變化,在發送一次請求之後,纔會觸發。
定義規則介紹
流控規則
閾值類型/單機閾值
- QPS(每秒鐘請求數量): 當調⽤該資源的QPS達到閾值時進⾏限流
- 線程數: 當調⽤該資源的線程數達到閾值的時候進⾏限流(線程處理請求的時候,如果說業務邏輯執⾏
時間很⻓,流量洪峯來臨時,會耗費很多線程資源,這些線程資源會堆積,最終可能造成服務不可⽤,
進⼀步上游服務不可⽤,最終可能服務雪崩)
是否集羣: 是否集羣限流
流控模式
- 直接: 資源調⽤達到限流條件時,直接限流
- 關聯: 關聯的資源調⽤達到閾值時候限流⾃⼰
- 鏈路: 只記錄指定鏈路上的流量
流控效果
- 快速失敗: 直接失敗,拋出異常
- Warm Up: 根據冷加載因⼦(默認3)的值,從閾值/冷加載因⼦,經過預熱時⻓,才達到設置的QPS閾值
- 排隊等待: 勻速排隊,讓請求勻速通過,閾值類型必須設置爲QPS,否則⽆效
降級規則
Sentinel會在某個資源不穩定時進行降級,在接下來的時間窗口內都進行熔斷(不會像Hystrix那樣放過⼀個請求嘗試⾃我修復,熔斷觸發後,時間窗⼝內拒絕所有請求,時間窗⼝結束後纔會恢復)。
- RT(平均響應時間): 當 1s 內持續進⼊ >=5 個請求,平均響應時間超過閾值(以 ms 爲單位),那麼在接下的時間窗口(以 s 爲單位)之內,對這個⽅法的調⽤都會⾃動地熔斷(拋出 DegradeException)。注意Sentinel 默認統計的 RT 上限是 4900 ms,超出此閾值的都會算作 4900 ms,若需要變更此上限可以通過啓動配置項 -Dcsp.sentinel.statistic.max.rt=xxx 來配置。
- 異常比例: 當資源的每秒請求量 >= 5,並且每秒異常總數佔通過量的⽐值超過閾值之後,資源進⼊降級狀態,即在接下的時間窗⼝(以 s 爲單位)之內,對這個⽅法的調⽤都會⾃動地返回。異常⽐率的閾
值範圍是 [0.0, 1.0] ,代表 0% - 100% - 異常數: 當資源近 1 分鐘的異常數⽬超過閾值之後會進⾏熔斷。注意由於統計時間窗⼝是分鐘級別的,若timeWindow ⼩於 60s,則結束熔斷狀態後仍可能再進⼊熔斷狀態。時間窗⼝ >= 60s
熱點規則
可以通過參數在限制接口訪問,針對熱點數據做限流,
場景:比如一些比較火的商品,頻繁訪問的商品可以利用這個限流
授權規則
設置允許調用的黑白名單
系統規則
比如針對cpu佔用多少時進行控制,這裏是全局控制,使用的場景也比較少
Sentinel自定義兜底方法
@SentinelResource
註解類似於Hystrix中的@HystrixCommand
註解
/**
* @SentinelResource value:定義資源名
* blockHandlerClass:指定Sentinel規則異常兜底邏輯所在class類
* blockHandler:指定Sentinel規則異常兜底邏輯具體哪個⽅法
* fallbackClass:指定Java運⾏時異常兜底邏輯所在class類
* fallback:指定Java運⾏時異常兜底邏輯具體哪個⽅法
*/
@GetMapping("/checkState/{userId}")
@SentinelResource(value = "findUserState",
blockHandlerClass = SentinelFallbackClass.class,
blockHandler = "handleException",
fallback ="handleError",
fallbackClass = SentinelFallbackClass.class)
public Integer findUserState(@PathVariable Long userId) {
// 模擬降級:
/*
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
*/
// 模擬降級:異常⽐例
int i = 1 / 0;
Integer defaultUserState = resumeServiceFeignClient.findDefaultUserState(userId);
return defaultUserState;
}
⾃定義兜底邏輯類
public class SentinelHandlersClass {
// 整體要求和當時Hystrix⼀樣,這⾥還需要在形參最後添加BlockException參數,⽤於接收異常
// 注意:⽅法是靜態的
public static Integer handleException(Long userId, BlockException
blockException) {
return -100;
}
public static Integer handleError(Long userId) {
return -500;
}
}
Sentinel規則持久化
我們在Sentinel Dashboard中定義的規則全部存儲在內存中,這會導致一個問題,當我們將Sentinel重啓後,之前定義的規則就會消失,這在生產環境下對我們來說是很不方便的,我們可以藉助nacos的配置中心,nacos可以將配置信息持久化到數據庫,從而達到我們將Sentinel規則持久化的目的。
在微服務項目中引入依賴:
<!-- Sentinel⽀持採⽤ Nacos 作爲規則配置數據源,引⼊該適配依賴 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
修改配置文件
server:
port: 8080
spring:
application:
name: cloud-service-user
main:
allow-bean-definition-overriding: true
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
sentinel:
transport:
dashboard: 127.0.0.1:8090# sentinel dashboard/console 地址
port: 8719
###############################################新增部分start###################################
# Sentinel Nacos數據源配置,Nacos中的規則會自動同步到sentinel流控規則中
datasource:
# 自定義的流控規則數據源名稱
flow:
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
data-id: ${spring.application.name}-flow-rules
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow # 類型來自RuleType類
# 自定義的降級規則數據源名稱
degrade:
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
data-id: ${spring.application.name}-degrade-rules
groupId: DEFAULT_GROUP
data-type: json
rule-type: degrade # 類型來自RuleType類
########################################新增部分end###########################################
jpa:
database: MySQL
show-sql: true
hibernate:
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl #避免將駝峯命名轉換爲下劃線命名
management:
endpoints:
web:
exposure:
include: "*"
# 暴露健康接口的細節
endpoint:
health:
show-details: always
nacos中添加對應規則配置信息
流控規則配置集 cloud-user-service-flow-rules
[
{
"resource":"findUserState",
"limitApp":"default",
"grade":1,
"count":1,
"strategy":0,
"controlBehavior":0,
"clusterMode":false
}
]
resource: 資源名稱
limitApp: 來源應⽤
grade: 閾值類型 0 線程數 1 QPS
count: 單機閾值
strategy: 流控模式,0 直接 1 關聯 2 鏈路
controlBehavior: 流控效果,0 快速失敗 1 Warm Up 2 排隊等待
clusterMode: true/false 是否集羣
降級規則配置集 cloud-user-service-degrade-rules
[
{
"resource":"findUserState",
"grade":2,
"count":1,
"timeWindow":5
}
]
resource: 資源名稱
grade: 降級策略 0 RT 1 異常⽐例 2 異常數
count: 閾值
timeWindow: 時間窗
*以上規則的可以在源碼Rule接口的實現類中查看