(一)Sentinel 簡介
(1)隨着微服務的普及,服務調用的穩定性變得越來越重要。Sentinel 以“流量”為突破口,在流量控制、熔斷降級、負載保護等多個領域進行工作,保障服務可靠性。通俗:用來在微服務系統中保護微服務的作用,如何應對 服務雪崩 服務熔斷 服務降級 就是用來替換 Hystrix;
(2)特性
- 豐富的應用場景:Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的范圍)、消息削峰、集群流量控制、實時熔斷下游不可用應用等;
- 完備的實時監控:Sentinel 同時提供實時的監控功能,您可以在控制台中看到接入應用的單台機器秒級數據,甚至 500 台以下規模的集群匯總運行情況;
- 廣泛的開源生態:Sentinel 提供開箱即用的與其它開源框架 / 庫的整合模塊,例如與 Spring Cloud、Dubbo、RPC 的整合,您只需要引入相應的依賴並進行簡單的配置即可快速地接入 Sentinel。
(二)Sentinel 下載安裝
(1)下載地址:Sentinel版本地址
(2)我選擇 sentinel-dashboard-1.8.1.jar
(3)移動到指定目錄,通過運行 Jar 包的命令執行 sentinel-dashboard-1.8.1.jar
手動指定端口后台運行:nohup java -Dserver.port=8888 -jar sentinel-dashboard-1.8.1.jar > catalina.out 2>&1 &
查看日志命令:tail -f catalina.out
(4)瀏覽器地址欄:http://localhost:8888 輸入默認的用戶名和密碼 sentinel 登記成功
(三)Sentinel 實時監控服務
(1)創建項目引入依賴
<!--引入nacos client 依賴,服務注冊與發現--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--引入sentinel 依賴 服務監控--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
(2)配置文件中寫配置
server.port=8789 # 指定服務名稱【默認和應用名稱同名】 spring.application.name=nacosclient # 1)先聲明 nacos 的注冊中心地址;2)服務發現【客戶端】進行注冊,引用的就是注冊中心的地址; spring.cloud.nacos.server-addr=localhost:8848 spring.cloud.nacos.discovery.server-addr=${spring.cloud.nacos.server-addr} # 暴露所有web端點【 nacos client 需要和其他微服務做通信,需要健康檢查】 management.endpoints.web.exposure.exclude='*' # sentinel dashboard 8888 外部訪問儀表盤界面的端口 和 sentinel logs 8719 內部服務的通信端口 # 此時 nacos-client 服務調用時產生的日志信息就會傳遞給 sentinel 進行展示,進而對服務進行流量控制、熔斷降級、負載保護 spring.cloud.sentinel.enabled=true spring.cloud.sentinel.transport.dashboard=localhost:8888 spring.cloud.sentinel.transport.port=8719
注意:項目啟動后,該微服務會自動交給 Sentinel 流量衛兵進行管理,但是訪問 Dashboard 界面查看服務監控,發現界面什么都沒有?
默認情況下 Sentinel 為延遲加載,不會在啟動之后立即創建服務監控,需要對服務進行調用時才會初始化;
也可以在微服務啟動時,手動加入配置:spring.cloud.sentinel.eager=true 此時 Sentinel 立即加載該微服務,而非延遲加載。
(3)編寫簡單測試 demo
@RestController @Slf4j public class SentinelController { @GetMapping("/sentinel/test") public String test(){ log.info("sentinel test"); return "sentinel test "; } @GetMapping("/sentinel/test1") public String test1(){ log.info("sentinel test1"); return "sentinel test1 "; } }
(4)調用該微服務時,會出現 QPS 的調用量
(四)S
- 流量控制(flow control),其原理是監控應用流量的 QPS 或並發線程數等指標,當達到指定的閾值時對流量進行控制,以避免被瞬時的流量高峰沖垮,從而保障應用的高可用性;
- 同一個資源可以創建多條限流規則。FlowSlot 會對該資源的所有限流規則依次遍歷,直到有規則觸發限流或者所有規則遍歷完畢;
- 一條限流規則主要由下面幾個因素組成,我們可以組合這些元素來實現不同的限流效果;
resource:資源名,即限流規則的作用對象 【服務路徑 /test/test 還可以給服務路徑起別名】
count: 限流閾值
grade: 限流閾值類型(QPS 或並發線程數)
limitApp: 流控針對的調用來源,若為 default 則不區分調用來源
strategy: 調用關系限流策略 【直接 關聯 鏈路】
controlBehavior: 流量控制效果(直接拒絕、Warm Up、勻速排隊)
- 流量控制主要有兩種統計類型,一種是統計並發線程數,另外一種則是統計 QPS 。
(2)配置 QPS 流量控制
(3)QPS 測試,每秒只能接收 1 個請求,超過 1 個就會報錯
(4)配置並發線程數限流【測試需要結合 jmeter 壓力測試工具,可以先開啟 10 個並發線程訪問 /test/test1,然后手動在瀏覽器訪問該路徑,可以測試出限流效果】
(5)流控模式
- 直接:標識流量控制規則到達閾值直接觸發流量控制;
- 關聯: 當兩個資源之間具有資源爭搶或者依賴關系的時候,這兩個資源便具有了關聯。比如對數據庫同一個字段的讀操作和寫操作存在爭搶,讀的速度過高會影響寫得速度,寫的速度過高會影響讀的速度。如果放任讀寫操作爭搶資源,則爭搶本身帶來的開銷會降低整體的吞吐量。可使用關聯限流來避免具有關聯關系的資源之間過度的爭搶,舉例來說,read_db 和 write_db 這兩個資源分別代表數據庫讀寫,我們可以給 read_db 設置限流規則來達到寫優先的目的:設置 strategy 為 RuleConstant.STRATEGY_RELATE 同時設置 refResource 為 write_db。這樣當寫庫操作過於頻繁時,讀數據的請求會被限流。
- 鏈路限流:wiki 解釋地址
(6)流控效果 wiki 解釋地址
- 直接拒絕:(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式是默認的流量控制方式,當QPS超過任意規則的閾值后,新的請求就會被立即拒絕,拒絕方式為拋出FlowException;
- Warm Up:(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即預熱/冷啟動方式。當系統長期處於低水位的情況下,當流量突然增加時,直接把系統拉升到高水位可能瞬間把系統壓垮。通過"冷啟動",讓通過的流量緩慢增加,在一定時間內逐漸增加到閾值上限,給冷系統一個預熱的時間,避免冷系統被壓垮;
- 勻速排隊:(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式會嚴格控制請求通過的間隔時間,也即是讓請求以均勻的速度通過,對應的是漏桶算法。只能對請求進行排隊等待。
(五)熔斷降級 熔斷降級wiki地址
(1)除了流量控制以外,對調用鏈路中不穩定的資源進行熔斷降級也是保障高可用的重要措施之一。由於調用關系的復雜性,如果調用鏈路中的某個資源不穩定,最終會導致請求發生堆積。Sentinel 熔斷降級會在調用鏈路中某個資源出現不穩定狀態時(例如調用超時或異常比例升高),對這個資源的調用進行限制,讓請求快速失敗,避免影響到其它的資源而導致級聯錯誤。當資源被降級后,在接下來的降級時間窗口之內,對該資源的調用都自動熔斷(默認行為是拋出 `DegradeException`)。
(2)降級策略【可以自行實踐一下,平均響應時間可以借用 jmeter 壓力工具進行實踐,異常比例和異常數可以自行在程序中處理即可測試效果】
(4)@SentinelResource 注解代碼測試【自行配置 流量控制,服務降級,執行程序邏輯處理的友好提示邏輯即可】
@GetMapping("/test/test") @SentinelResource(value = "aa", fallback = "testFallBack", blockHandler = "testBlockHandler") public String test(int id) { if (id < 0 ) { throw new RuntimeException("參數錯誤!!!"); } log.info("進入 test 服務"); return "test 服務調用成功"; } // 程序邏輯出現異常友好提示【在界面上就不會出現異常堆棧信息,不友好,直接提示: id 為非法參數,請檢查重新嘗試】 public String testFallBack(int id) { return id + " 為非法參數,請檢查重新嘗試!!!"; } // 流控異常自定義信息方法 public String testBlockHandler(int id, BlockException blockException) { if (blockException instanceof FlowException) { return "活動異常火爆,當前請求被限流!!!" + blockException.getClass().getSimpleName(); } if (blockException instanceof DegradeException) { return "當前服務已被降級處理,請稍后再試!!!" + blockException.getClass().getSimpleName(); } return "當前服務不可用!!!"; }
年少輕狂的我,每天進步一點點......