Sentinel 是什么?
Sentinel 具有以下特征:
豐富的應用場景:Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的范圍)、消息削峰填谷、集群流量控制、實時熔斷下游不可用應用等。
完備的實時監控:Sentinel 同時提供實時的監控功能。您可以在控制台中看到接入應用的單台機器秒級數據,甚至 500 台以下規模的集群的匯總運行情況。
廣泛的開源生態:Sentinel 提供開箱即用的與其它開源框架/庫的整合模塊,例如與 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相應的依賴並進行簡單的配置即可快速地接入 Sentinel。
完善的 SPI 擴展點:Sentinel 提供簡單易用、完善的 SPI 擴展接口。您可以通過實現擴展接口來快速地定制邏輯。例如定制規則管理、適配動態數據源等。
Sentinel 的主要特性:

Sentinel 的開源生態:

我們大概敘述后開始整合我們的分布式項目,我這里里為一個簡單分布式項目,注冊中心為Nacos,一個服務提供者(user-center)和一個服務消費者(content-center)
import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import java.util.List; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; @Slf4j @Service @RequiredArgsConstructor(onConstructor = @__(@Autowired)) public class ShareService { private final ShareMapper shareMapper; private final RestTemplate restTemplate; public ShareDTO findById(Integer id) { // 獲取分享詳情 Share share = this.shareMapper.selectByPrimaryKey(id); // 發布人id Integer userId = share.getUserId(); UserDTO userDTO = this.restTemplate.getForObject( "http://user-center/users/{userId}", UserDTO.class, userId ); ShareDTO shareDTO = new ShareDTO(); // 消息的裝配 BeanUtils.copyProperties(share, shareDTO); // shareDTO.setWxNickname(userDTO.getWxNickname()); return shareDTO; } }
可以看到我的content-center調用user-center/users服務
import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/shares") @RequiredArgsConstructor(onConstructor = @__(@Autowired)) public class ShareConroller { private final ShareService shareService; @GetMapping("/{id}") public ShareDTO findById(@PathVariable Integer id) { return this.shareService.findById(id); } }
我們現在只啟動content-center不啟動user服務,可想而知肯定報錯,我們來看

沒錯500,找不到user-center服務,我們現在整合Sentinel,首先加入兩個依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-alibaba-sentinel</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
和actuator配合使用,可通過http://localhost:8010/actuator/sentinel端點進行查看
{ "blockPage":null, "appName":"content-center", "consoleServer":"localhost:8333", "coldFactor":"3", "rules":{ "systemRules":[ ], "authorityRule":[ ], "paramFlowRule":[ ], "flowRules":[ ], "degradeRules":[ ] }, "metricsFileCharset":"UTF-8", "filter":{ "order":-2147483648, "urlPatterns":[ "/*" ], "enabled":true }, "totalMetricsFileCount":6, "datasource":{ }, "clientIp":"192.168.2.29", "clientPort":"8719", "logUsePid":false, "metricsFileSize":52428800, "logDir":"/Users/zhangguowei/logs/csp/", "heartbeatIntervalMs":10000 }
我們暫時先不要管這些是什么我們后面再詳細闡述,從JSON的形式看不太方便,Sentinel為我們整合有UI界面
整合Sentinel可視化界面
下載 sentinel的jar包然后直接啟動https://github.com/alibaba/Sentinel/releases

啟動的時候可以自定義端口號

賬號密碼默認為sentinel,在項目的yml中加入
spring: datasource: url: jdbc:mysql://localhost:3306/content_center hikari: username: *** password: ****** driver-class-name: com.mysql.cj.jdbc.Driver cloud: sentinel: transport: # 指向sentinel UI界面 dashboard: localhost:8333 nacos: discovery: # 指定nacos server的地址 server-addr: localhost:8848 application: # 服務名稱盡量用-,不要用_,不要用特殊字符 name: content-center server: port: 8010 management: endpoints: web: exposure: include: "*"
這個時候我們繼續剛剛的500再執行幾次會看到

相對於原來的Hystrix 的UI界面 Sentinel更人性化

他支持QPS的查看,請求時間等等

那么我們首先來探討流控規則,我們現在把user服務也啟動,我們點擊簇點鏈路

可以看到content曾經訪問過的路徑,我們點擊流控按鈕,就可以為這路徑設置流控規則

我們可以看到資源名默認為我們請求的路徑,其實也不一定是路徑,他只是做唯一標識,
針對來源:Sentinel可以針對調用者進行限流控制,比如兩個服務調用content服務,我可以把針對來源寫為A然后設置QPS的閾值為200,B為300QPS,也就是我當前訪問的API接口對不同的服務有不同的限流規則,那么就可以用針對來源來設置,我們暫時用default,標識不區分來源,后面詳細說如何區分來源。

閾值類型有兩個選項,分別是QPS和線程數,如果選擇QPS然后設置閾值,就是當這個API達到這個QPS閾值時會進行限流,同理也可以使用線程數限流,當達到一定的線程數的時候進行限流,是否集群我們在后面會詳細探討。
流控模式,sentinel提供了三種流控模式,我們先來看直接我們設置直接並保存

可以看到訪問一次直接再次訪問就直接限流了。那關聯是什么意思,也就是說當關聯的資源達到閾值,就限流自己,我們來嘗試,剛剛上面所說我們可以用http://localhost:8010/actuator/sentinel 來查看信息,我們用/shares/1關聯actuator/sentinel

它表示actuator/sentinel這個端點達到這個閾值那么就限流/shares/1這個路徑,
我們來寫段測試代碼
import org.springframework.web.client.RestTemplate; public class SentinelTest { public static void main(String[] args) { RestTemplate restTemplate = new RestTemplate(); for (int i = 0; i <10000 ; i++) { String forObject = restTemplate.getForObject("http://localhost:8010/actuator/sentinel", String.class); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } }
理論上這樣調用的話QPS肯定大於1,那么此時/shares/1會被限流

此時/shares/1會一直處於限流狀態,他適用於什么場景:比如一個請求查詢shares一個來修改shares處於高並發狀態,查詢過快的話會影響修改的性能,修改快的話會影響查詢性能,所以這個時候可以根據業務場景,是希望優先讀還是優先改,如果我們希望優先改,我們可以把關聯的資源寫成修改的API,資源名設置為查詢API,這樣修改超過閾值的話查詢就會被限流。總的來說關聯就是保護關聯資源的設計。
我們繼續來說第三個模式

點擊鏈路會變成入口資源,鏈路:只記錄指定鏈路上的流量,指定資源從入口資源進來的流量達到閾值就會限流,我們繼續寫代碼來測試

這里用到@SentinelResource注解,后續我們會說到

我們訪問后點擊簇點鏈路

會發現有testa和testb

以及common
我們在common上面點擊流控

我們把入口寫testa

第一次請求正常請求

請求多次后直接500被限流而testb無論怎么請求都會正常請求,
這其實就是細粒度的針對來源,我們上面所說的針對來源是微服務級別而鏈路是API級別的。那現在我們三種流控模式都嘗試完畢,我們恢復成直接狀態,最后我們來探討流控效果

快速失敗很好理解,就是直接拋異常,在測試當中我們也看到了,他的源碼在com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController 目錄中

第二種叫Warm Up
什么意思呢?就是說sentinel也有個默認值為3,從閾值/3,經過預熱時長,才到達設置的QPS閾值。也就是說,我把閾值設置為100我把預熱時長設置為10秒

那么他就會用100除3作為最初的閾值,然后經過10秒之后才去達到這個100限流。比如有一個秒殺微服務,平常的並發並不是很高,但是在某一個瞬間,某一場秒殺活動開始,在開始的瞬間流量會激增,如果不做任何處理,可能服務一下就宕了,所以Sentinel設計Warm Up這種模式,可以讓允許通過的流量緩慢的增加,在經過10秒之后才達到設定的閾值,這樣就會更好的保護我們的微服務
相關源碼在:com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController
我們來看最后一種效果

這個是排隊等待,這個也很好理解就是 勻速排隊,讓請求以均勻的速度通過,但是閾值的類型必須設置為QPS,否則都無效了
也就說比如我閾值100,60只允許閾值為100,其他的請求在后面排隊直到設置的超時時間,如果過了超時時間求丟棄這次請求,這里我就不再做實驗,他比較適用於突發流量場景,比如你的系統突然來了好多流量,一會就比較少,你希望應用在空閑的時候處理請求而不直接拒絕就可以使用排隊等待。這個模式的源碼路徑為:
com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController
暫時先說到這里 sentinel提供很多非常靈活,而且還有強大的限流規則。
