這篇文章介紹一下阿里開源的流量防衛兵Sentinel,一款非常優秀的開源項目,經過近10年的雙十一的考驗,非常成熟的一款產品。
文章目錄如下:
圖片
sentinel顧名思義:衛兵;在Redis中叫做哨兵,用于監控主從切換,但是在微服務中叫做流量防衛兵。
Sentinel 以流量為切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性。
Sentinel 具有以下特征:
Sentinel 的主要特性如下圖:
圖片
Sentinel 分為兩個部分:
總之一句話:sentinel真牛逼,完爆Hystrix.........
不多說了,總之一句話:Hystrix趕緊放棄,用sentinel......
具體區別如下圖:
圖片
由于陳某寫的是Spring Cloud 進階一個系列,使用的聚合項目,因此版本還是保持和之前文章一樣,不清楚的可以看這篇:五十五張圖告訴你微服務的靈魂擺渡者Nacos究竟有多強?
這里選擇的spring-cloud-alibaba-dependencies的版本是2.2.1.RELEASE,因此sentinel版本選擇1.7.1,大家可以根據自己的版本選擇對應sentinel的版本,版本對應關系如下圖:
圖片
注意:一定要按照官方推薦的版本適配,否則出現意想不到的BUG追悔莫及.........
sentinel和nacos一樣,都有一個控制臺,但是這里不用自己手動搭建一個微服務,官方已經搭建好了,只需要下載對應得jar包運行即可。下載地址:https://github.com/alibaba/Sentinel/tags
選擇對應得版本下載即可,我這里選擇1.7.1版本,下載的jar包如下圖:
圖片
當然你可以通過源碼構建:mvn clean package。
注意:JDK版本必須>=1.8
此時我們只需要運行這個jar包即可,命令如下:
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.1.jar
上述參數含義如下:
啟動成功之后,瀏覽器訪問:http://localhost:8080,登錄頁面如下圖:
默認的用戶名和密碼:sentinel/sentinel
登錄成功之后頁面如下:
圖片
可以看到目前只有一個服務sentinel-dashboard被監控了,這個服務就是自己。
注意:上述參數都是可選的,沒必要可以不填。
那么問題來了:默認的用戶名和密碼在生產環境上肯定不能用,如何修改呢?
從 Sentinel 1.6.0 起sentinel已經支持自定義用戶名和密碼了,只需要在執行jar命令時指定即可,命令如下:
java -Dsentinel.dashboard.auth.username=admin -Dsentinel.dashboard.auth.password=123 -jar sentinel-dashboard-1.7.1.jar
用戶可以通過如下參數進行配置:
注意:部署多臺控制臺時,session 默認不會在各實例之間共享,這一塊需要自行改造。
除了用戶名密碼相關的配置,sentinel控制臺還提供了其他的可配置選項,如下圖:
圖片
微服務為什么要集成sentinel控制臺,sentinel不是提供了相關的API嗎?
其實Spring Boot 官方一直提倡約定>配置>編碼的規則,能夠不硬編碼何樂而不為呢?
因此本文后續內容主要還是結合sentinel控制臺進行講解,關于API的使用大家可以按照官方文檔學習,講解的非常清楚。
好了,言歸正傳,微服務如何接入sentinel控制臺呢?
這里的注冊中心依然使用的是nacos,有不會用的請看專欄第一篇Nacos文章:五十五張圖告訴你微服務的靈魂擺渡者Nacos究竟有多強?
新建一個微服務模塊:sentinel-service9008,相關代碼不貼出了。
相關配置如下:
server: port: 9008spring: application: ## 指定服務名稱,在nacos中的名字 name: sentinel-service cloud: nacos: discovery: # nacos的服務地址,nacos-server中IP地址:端口號 server-addr: 127.0.0.1:8848management: endpoints: web: exposure: ## yml文件中存在特殊字符,必須用單引號包含,否則啟動報錯 include: '*'
源碼全部會上傳,獲取方式看文末!
除了Nacos的依賴,還需要添加一個sentinel的依賴:
<!--sentinel的依賴--><dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency>
以上只貼出了sentinel相關依賴,nacos依賴不再貼了,見源碼!
只需要添加如下配置即可集成sentinel控制臺:
spring: cloud: sentinel: transport: ## 指定控制臺的地址,默認端口8080 dashboard: localhost:8080
下面新建一個測試接口,用于測試相關規則,如下:
@RestController@RequestMapping("/sentinel")public class FlowLimitController { @GetMapping("/test") public String test(){ return "接收到一條消息--------"; }}
啟動9008這個微服務,然后瀏覽器輸入:http://localhost:9008/sentinel/test,此時查看sentinel控制臺,將會看見sentinel-service這個服務已經被監控了,如下圖:
圖片
注意:sentinel是懶加載機制,只有訪問過一次的資源才會被監控。
不過可以通過配置關閉懶加載,在項目啟動時就連接sentinel控制臺,配置如下:
spring: sentinel: # 取消控制臺懶加載,項目啟動即連接Sentinel eager: true
流量控制(flow control),其原理是監控應用流量的 QPS 或并發線程數等指標,當達到指定的閾值時對流量進行控制,以避免被瞬時的流量高峰沖垮,從而保障應用的高可用性。
QPS:每秒請求數,即在不斷向服務器發送請求的情況下,服務器每秒能夠處理的請求數量。
并發線程數:指的是施壓機施加的同時請求的線程數量。
同一個資源可以創建多條限流規則,一條限流規則由以下元素組成:
以上元素限流元素對應的類是com.alibaba.csp.sentinel.slots.block.flow.FlowRule,各元素如下圖:
圖片
注意:各個元素的取值以及默認值一定要記住,后續配置將會用到。
以上幾個元素在sentinel控制臺對應規則如下圖:
圖片
流控效果總共分為三種,對應元素controlBehavior,分別如下:
默認的流量控制方式,當QPS超過任意規則的閾值后,新的請求就會被立即拒絕,拒絕方式為拋出FlowException。
即預熱/冷啟動方式。當系統長期處于低水位的情況下,當流量突然增加時,直接把系統拉升到高水位可能瞬間把系統壓垮。通過"冷啟動",讓通過的流量緩慢增加,在一定時間內逐漸增加到閾值上限,給冷系統一個預熱的時間,避免冷系統被壓垮。
注意:這一效果只針對QPS流控,并發線程數流控不支持。
預熱底層是根據令牌桶算法實現的,源碼對應得類在com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController。
算法中有一個冷卻因子coldFactor,默認值是3,即請求 QPS 從 threshold(閾值) / 3 開始,經預熱時長逐漸升至設定的 QPS 閾值。
比如設定QPS閾值為3,流控效果為warm up,預熱時長為5秒,如下圖:
圖片
這樣配置之后有什么效果呢:QPS起初會從(3/3/=1)每秒通過一次請求開始預熱直到5秒之后達到每秒通過3次請求。動態效果圖如下:
圖片
從上述動畫可以清楚的看見:前幾秒是頻繁流控的,直到5秒,QPS閾值達到了3。
具體算法原理請看:https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81---%E5%86%B7%E5%90%AF%E5%8A%A8
勻速排隊方式會嚴格控制請求通過的間隔時間,也即是讓請求以均勻的速度通過,對應的是漏桶算法。源碼對應得類:com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController
注意:這一效果只針對QPS流控,并發線程數流控不支持。
簡單舉個栗子:你去大學食堂吃飯,只有一個阿姨在打飯,那么所有人都要排隊打飯,每次只有一個人打到飯,其他人都在排隊等待。
不同的是sentinel有個超時等待時間,一旦超過這個預定設置的時間將會被限流。
該方式作用如下圖:
圖片
這種方式適合用于請求以突刺狀來到,這個時候我們不希望一下子把所有的請求都通過,這樣可能會把系統壓垮;同時我們也期待系統以穩定的速度,逐步處理這些請求,以起到“削峰填谷”的效果,而不是拒絕所有請求。
比如設置QPS閾值為1,超時等待時間為10000毫秒,如下圖:
圖片
此時的效果如下:
從上圖可以看到:連續點擊刷新請求,雖然設置了QPS閾值為1,但是并沒有被限流,而是在等待,因為設置了超時等待時間為10秒。
具體算法原理請看:https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6-%E5%8C%80%E9%80%9F%E6%8E%92%E9%98%9F%E6%A8%A1%E5%BC%8F
流控模式總共分為三種,對應元素strategy,分別如下:
下面來詳細介紹下以上三種流控模式。
顧名思義:默認的流量控制方式,當QPS超過任意規則的閾值后,新的請求就會被立即拒絕,拒絕方式為拋出FlowException。上面的幾個例子都是配置了直接拒絕這個模式,這里不再詳細介紹。
典型的使用場景:一個是支付接口,一個是下單接口,此時一旦支付接口達到了閾值,那么訂單接口就應該被限流,不然這邊還在下單,消費者等待或者直接被拒絕支付將會極大的影響用戶體驗。
簡而言之:A關聯B,一旦B達到閾值,則A被限流
演示一下效果,創建以下兩個接口:
@RestController@RequestMapping("/sentinel")public class FlowLimitController { /** * 下單接口 * @return */ @GetMapping("/order") public String order() { return "下單成功.........."; } /** * 支付接口 * @return */ @GetMapping("/pay") public String pay() { return "支付成功.........."; }}
此時的流控規則配置如下圖:
圖片
注意:關聯之后,這里設置的限流規則是對被關聯資源,也就是/sentinel/pay這個資源,但是真正被限流則是/sentinel/order。
如何演示效果呢?很簡單,只需要不斷的請求/sentinel/pay達到閾值,然后在請求/sentinel/order。
利用POSTMAN不斷向/sentinel/pay發出請求,然后瀏覽器請求/sentinel/order,結果如下圖:
圖片
可以看到訂單接口被限流了.............
流控分為兩種統計類型,分別是QPS,并發線程數,很多人不太明白這兩種統計類型有什么區別?
舉個栗子:陳某帶了一個億去銀行存錢,但是銀行大門保安要查健康碼,每秒最多只能同時進入4個人,并且銀行中只有兩個工作人員工作,如下圖:
圖片
此時的QPS含義:從保安到銀行這一段,即是保安放行進入銀行的人數。
此時并發線程數的含義:銀行只有兩個工作人員在工作,那么最多只能同時處理兩個任務,這里并發線程數的閾值就是2。
熔斷降級在日常生活中也是比較常見的,場景如下:
在大型的分布式系統中,一個請求的依賴如下圖:
圖片
如果這個時候,某個服務出現一些異常,比如:
那么將會導致整個服務不可用,用古話來講就是:千里之堤毀于蟻穴。
所謂編程源于生活,架構師們根據生活的經驗設計出了服務的熔斷降級策略,很好的解決了這類問題。
熔斷降級規則對應sentinel控制臺的降級規則這一欄,如下圖:
圖片
熔斷降級涉及到的幾個屬性如下表:
圖片
源碼中對應得類為:com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule。
Sentinel 提供以下幾種熔斷策略:
下面演示一個平均響應時間熔斷,創建一個接口,如下:
@RestController@RequestMapping("/sentinel/provider")@Slf4jpublic class FlowLimitController { @GetMapping("/test") public String test() throws InterruptedException { //休眠3秒鐘 Thread.sleep(3000); log.info("收到一條消息----test"); return "接收到一條消息--------"; }}
在控臺為這個接口設置平均響應時間為200毫秒,時間窗口為1秒,大致意思:平均的響應時間大于200毫秒之后,在接下來的1秒時間內將會直接熔斷,如下圖:
圖片
使用Jmeter開啟10個線程循環跑,然后在瀏覽器中訪問這個接口,返回結果如下圖:
圖片
為什么呢?由于的接口中休眠了3秒,平均響應時間肯定大于200毫秒,因此直接被熔斷了。
注意:這里熔斷后直接返回默認的信息,后面會介紹如何定制熔斷返回信息。
顧名思義:熱點就是經常訪問的數據,很多時候肯定是希望統計某個訪問頻次Top K數據并對其進行限流。
比如秒殺系統中的商品ID,對于熱點商品那一瞬間的并發量是非常可怕的,因此必須要對其進行限流。
Sentinel 利用 LRU 策略統計最近最常訪問的熱點參數,結合令牌桶算法來進行參數級別的流控。
注意:熱點參數限流只針對QPS。
官方文檔:https://github.com/alibaba/Sentinel/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6%B5%81
概念理解了,來看下sentinel控制臺如何設置熱點參數限流,如下圖:
圖片
規則對應得源碼在com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule這個類中,各種屬性含義如下圖:
圖片
規則都懂了,下面我們通過實戰來演示一下熱點參數到底是如何限流的。
注意:熱點參數限流只作用于八大基本類型。
現在先創建一個service,用@SentinelResource這個注解定義一個資源,這個注解后續將會詳細介紹,先忽略,代碼如下:
@Service@Slf4jpublic class FlowServiceImpl implements FlowService { /** * @SentinelResource的value屬性指定了資源名,一定要唯一 * blockHandler屬性指定了兜底方法 */ @Override @SentinelResource(value = "OrderQuery",blockHandler = "handlerQuery") public String query(String p1, String p2) { log.info("查詢商品,p1:{},p2:{}",p1,p2); return "查詢商品:success"; } /** * 對應得兜底方法,一旦被限流將會調用這個方法來處理 */ public String handlerQuery(@RequestParam(value = "p1",required = false) String p1, @RequestParam(value = "p2",required = false)String p2, BlockException exception){ log.info("查詢商品,p1:{},p2:{}",p1,p2); return "查詢商品:熔斷了......"; }}
上述代碼什么意思呢?如下:
下面創建一個controller進行測試,代碼如下:
@RestController@RequestMapping("/sentinel/provider")@Slf4jpublic class FlowLimitController { @Autowired private FlowService flowService; @GetMapping("/order/query") public String query(@RequestParam(value = "p1",required = false) String p1, @RequestParam(value = "p2",required = false)String p2){ return flowService.query(p1,p2); }}
可以看到接口中有兩個參數,分別是p1、p2。
在sentinel控制臺點擊熱點規則->新增熱點限流規則,添加如下圖規則:
圖片
上述配置的具體含義:當OrderQuery這個資源中的第0個參數QPS超過1秒1次將會被限流。這里參數索引是從0開始,第0個就是對應接口中的p1這個參數。
第一個測試:瀏覽器直接訪問:http://localhost:9009/sentinel/provider/order/query?p1=22&p2=1222,連續點擊將會看到這個接口被熔斷降級了,如下圖:
圖片
這也正是驗證了上述的熱點參數限流配置。
第二個測試:瀏覽器輸入:http://localhost:9009/sentinel/provider/order/query?p2=1222,連續點擊將會看到這個接口并沒有被熔斷降級,如下圖:
圖片
注意:對于熱點參數限流,只有包含指定索引的參數請求才會被限流,否則不影響。
此時產品說:ID為100的這個產品點擊量太少了,你們趕緊調整下這個商品的限流規則。這個時候該怎么辦呢?
別著急,sentinel顯然考慮到了這一點,提供了參數例外項這項配置,針對產品需求配置如下:
圖片
從上圖配置中,我們將參數值p1這個參數值等于100的時候,限流閾值設置成了100,也就是說p1=100這個請求QPS放寬到1秒請求100次以上才會被限流。
驗證:瀏覽器輸入地址:http://localhost:9009/sentinel/provider/order/query?p1=100,無論點擊多么快,都沒有被熔斷降級,顯然是配置生效了,如下圖:
圖片
以上源碼在sentinel-openfeign-provider9009這個模塊中,文末有源碼獲取方式。
前面熱點參數、普通流量限流都是針對的某個接口,這里系統自適應限流針對是整個系統的入口流量,從單臺機器的 load、CPU 使用率、平均 RT、入口 QPS 和并發線程數等幾個維度監控應用指標,讓系統盡可能跑在最大吞吐量的同時保證系統整體的穩定性。
sentinel控制臺對應如下圖:
圖片
閾值類型有五種,分別如下:
官方文檔:https://github.com/alibaba/Sentinel/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81
系統規則的配置比較簡單,這里以入口QPS為例進行演示,為了演示真實情況,清掉所有的限流規則,添加系統規則,如下圖:
圖片
這個QPS系統規則一配置,該微服務中的所有接口都將會被這個規則限制,比如訪問:http://localhost:9009/sentinel/provider/pay,連續點擊,如下圖:
圖片
可以看到已經被限流了,不僅是這個接口,所有接口都會生效。
注意:系統規則中的入口QPS這個規則不建議配置,一旦配置上了可能導致整個服務不可用。
在前面的例子中,無論是熔斷降級還是被限流返回的異常信息都是Blocked by Sentinel (flow limiting),這個是Sentinel默認的異常信息。
很顯然默認的異常信息并不能滿足我們的業務需求,因此我們需要根據前后端規則制定自己的異常返回信息。
這里將會用到一個注解@SentinelResource,這個在上文也是提到過,這個注解中有兩個關于限流兜底方法的屬性,如下:
官方文檔:https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81
使用@SentinelResource注解自定義一個限流異常返回信息,先自定義一個資源,指定兜底方法為handler,代碼如下:
圖片
第二步:寫個對應得兜底方法,必須在同一個類中,代碼如下:
圖片
第三步:對資源QueryOrder新增一個限流規則,如下圖:
圖片
第四步:寫個controller,代碼就不曬了,自己寫吧,哈哈。。。。
第五步:調用接口,瘋狂點擊,將會出現兜底方法中定義的返回信息,如下圖:
圖片
到這兒基本算是成功了,但是有個問題:兜底方法必須要和業務方法放在同一個類中,這樣代碼耦合度不是很高嗎?
@SentinelResource提供一個屬性blockHandlerClass,完美的解決了這一個問題,能夠將兜底方法單獨放在一個類中,下面來介紹一下。
第一步:新建一個單獨的類CommonHandler來放置兜底方法,代碼如下:
圖片
第二步:在@SentinelResource注解中指定blockHandlerClass為上面的類,blockHandler指定兜底方法名,代碼如下:
圖片
好了,至此就完成了,自己照著試試吧.......
上述源碼在sentinel-openfeign-provider9009這個模塊中,源碼獲取方式見文末。
程序員每天都在制造BUG,沒有完美的代碼,也沒有完美的程序員,針對代碼的運行時異常我們無法避免,但是我們可以當出現異常的時候進行捕獲并做出相應的處理,我們稱之為降級處理。
異常的降級還是要用到@SentinelResource注解,其中相關的幾個屬性如下:
返回值類型必須與原函數返回值類型一致;
方法參數列表需要和原函數一致,或者可以額外多一個 Throwable 類型的參數用于接收對應的異常。
fallback 函數默認需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定 fallbackClass 為對應的類的 Class 對象
1.8.0 版本開始,defaultFallback 支持在類級別進行配置。
注:1.6.0 之前的版本 fallback 函數只針對降級異常(DegradeException)進行處理,不能針對業務異常進行處理。
官方文檔:https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81
下面定義一個創建訂單的接口,手動制造一個1/0異常,代碼如下:
圖片
上述接口并沒有進行異常降級處理,因此調用該接口直接返回了異常信息,非常不友好,如下圖:
圖片
我們可以使用fallback指定異常降級的兜底方法,此時業務方法改造如下:
圖片
使用fallbackClass屬性指定單獨一個類處理異常降級,降低了代碼的耦合度,fallback屬性指定了降級兜底的方法,代碼如下:
圖片
此時再次訪問接口,雖然有異常,但是返回的確實降級兜底方法中的返回信息,如下圖:
圖片
到了這里基本滿足了異常降級的處理需求,但是仍然有個疑問:能否只用一個方法處理全部的異常?
答案是:能,必須能,此時就要用到defaultFallback這個屬性了,指定默認的降級兜底方法,此時的業務方法變成如下代碼:
圖片
defaultFallback屬性指定了默認的降級兜底方法,這個方法代碼如下:
圖片
好了,異常降級處理到這兒已經介紹完了,但是仍然有一個問題:若 blockHandler 和 fallback 都進行了配置,那么哪個會生效?
結論:若 blockHandler 和 fallback 都進行了配置,則被限流降級而拋出 BlockException 時只會進入 blockHandler 處理邏輯。若未配置 blockHandler、fallback 和 defaultFallback,則被限流降級時會將 BlockException 直接拋出。
將createOrder這個業務接口改造一下,同時指定blockHandler和fallback,代碼如下:
圖片
此時不配置任何規則,直接訪問接口,可以看到這里直接進入了異常降級處理,如下圖:
圖片
我們對createOrder這個資源配置降級規則:60秒內如果出現2個以上的異常直接限流,如下圖:
圖片
此時我們再次訪問這個接口,可以看到前兩次直接進入了fallback指定的方法中(并未達到限流的異常數閾值),兩次之后就被限流了,進入了blockHandler方法中,效果如下圖:
圖片
上述源碼在sentinel-openfeign-provider9009這個模塊中,源碼獲取方式見文末。
顧名思義,黑名單就是拉黑唄,拉黑就是不能訪問了唄,sentinel能夠針對請求來源進行是否放行,若配置白名單則只有請求來源位于白名單內時才可通過;若配置黑名單則請求來源位于黑名單時不通過,其余的請求通過。
sentinel控制臺對應得規則配置如下圖:
圖片
該規則對應得源碼為com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule,幾個屬性如下:
官方文檔:https://github.com/alibaba/Sentinel/wiki/%E9%BB%91%E7%99%BD%E5%90%8D%E5%8D%95%E6%8E%A7%E5%88%B6
這里有個問題:請求來源是什么,怎么獲取?
Sentinel提供了一個接口RequestOriginParser,我們可以實現這個接口根據自己業務的規則解析出請求來源名稱。
下面我以IP作為區分請求來源,代碼如下:
圖片
然后將127.0.0.1設置為黑名單,如下圖:
圖片
直接訪問:http://127.0.0.1:9009/sentinel/rate/order/query?id=1002,結果如下圖:
圖片
可以看到被限流了哦.................
好了,黑白名單就介紹到這里。
上述源碼在sentinel-openfeign-provider9009這個模塊中,源碼獲取方式見文末。
Sentinel默認限流規則是存儲在內存中,只要服務重啟之后對應得限流規則也會消失,實際的生產中肯定是不允許這種操作,因此限流規則的持久化迫在眉睫。
sentinel官方文檔提供了兩種持久化模式,分別如下:
圖片
但是官方推薦使用Push模式,下面陳某就Push模式介紹一下持久化限流規則。這里使用Nacos作為配置中心。
盜用官方一張架構圖,如下:
圖片
這里需要添加一個依賴,如下:
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId></dependency>
既然使用到了Nacos作為配置中心,肯定是要配置相關的地址、dataId...
在application.yml配置文件中添加如下配置:
spring: cloud: sentinel: ## nacos持久化配置 datasource: ## 配置流控規則,名字任意 ds-flow: nacos: ## nacos的地址 server-addr: 127.0.0.1:8848 ## 配置ID dataId: ${spring.application.name}-flow ## 配置分組,默認是DEFAULT_GROUP groupId: DEFAULT_GROUP ## 配置存儲的格式 data-type: json ## rule-type設置對應得規則類型,總共七大類型,在com.alibaba.cloud.sentinel.datasource.RuleType這個枚舉類中有體現 rule-type: flow ## 配置降級規則,名字任意 ds-degrade: nacos: ## nacos的地址 server-addr: 127.0.0.1:8848 ## 配置ID dataId: ${spring.application.name}-degrade ## 配置分組,默認是DEFAULT_GROUP groupId: DEFAULT_GROUP ## 配置存儲的格式 data-type: json ## rule-type設置對應得規則類型,總共七大類型,在com.alibaba.cloud.sentinel.datasource.RuleType這個枚舉類中有體現 rule-type: degrade
上述配置僅僅展示了和持久化相關的一些配置,其他相關的配置代碼就不貼了,稍后自己看源碼。
spring.cloud.sentinel.datasource下可以配置多個規則,陳某這里只配置了限流和降級規則,其他規則自己嘗試配一下,不同規則通過rule-type區分,其取值都在com.alibaba.cloud.sentinel.datasource.RuleType這個枚舉類中,對應著sentinel中的幾大統計規則。
上述配置中對應的限流(flow)規則如下圖:
圖片
上述配置中對應的降級(degrade)規則如下圖:
圖片
先不糾結JSON數據里面到底是什么,先看效果,全部發布之后,Nacos中總共有了兩個配置,如下圖:
圖片
上圖中可以看到我們的兩種規則已經在Nacos配置好了,來看一下sentinel中是否已經生效了,如下圖:
圖片
哦了,已經生效了,由于是push模式,只要nacos中點擊發布配置,相關規則配置就會推送到sentinel中。
上述源碼在sentinel-openfeign-provider9009這個模塊中,源碼獲取方式見文末。
伏筆:push模式只能保證Nacos中的修改推送到sentinel控制臺,**但是sentinel控制臺的限流規則修改如何推送到Nacos呢?**別著急,下面將會介紹..............
很多人好奇JOSN中的配置到底怎么寫?其實很簡單,陳某在介紹各種規則的時候都明確告訴你每種規則對應源碼中的實現類,比如流控規則對應的類就是com.alibaba.csp.sentinel.slots.block.flow.FlowRule,JOSN中各個屬性也是來源于這個類。
下面陳某列出各個規則的JSON配置,開發中照著改即可。
[ { // 資源名 "resource": "/test", // 針對來源,若為 default 則不區分調用來源 "limitApp": "default", // 限流閾值類型(1:QPS;0:并發線程數) "grade": 1, // 閾值 "count": 1, // 是否是集群模式 "clusterMode": false, // 流控效果(0:快速失敗;1:Warm Up(預熱模式);2:排隊等待) "controlBehavior": 0, // 流控模式(0:直接;1:關聯;2:鏈路) "strategy": 0, // 預熱時間(秒,預熱模式需要此參數) "warmUpPeriodSec": 10, // 超時時間(排隊等待模式需要此參數) "maxQueueingTimeMs": 500, // 關聯資源、入口資源(關聯、鏈路模式) "refResource": "rrr" }]
[ { // 資源名 "resource": "/test1", "limitApp": "default", // 熔斷策略(0:慢調用比例,1:異常比率,2:異常計數) "grade": 0, // 最大RT、比例閾值、異常數 "count": 200, // 慢調用比例閾值,僅慢調用比例模式有效(1.8.0 引入) "slowRatioThreshold": 0.2, // 最小請求數 "minRequestAmount": 5, // 當單位統計時長(類中默認1000) "statIntervalMs": 1000, // 熔斷時長 "timeWindow": 10 }]
[ { // 資源名 "resource": "/test1", // 限流模式(QPS 模式,不可更改) "grade": 1, // 參數索引 "paramIdx": 0, // 單機閾值 "count": 13, // 統計窗口時長 "durationInSec": 6, // 是否集群 默認false "clusterMode": 默認false, // "burstCount": 0, // 集群模式配置 "clusterConfig": { // "fallbackToLocalWhenFail": true, // "flowId": 2, // "sampleCount": 10, // "thresholdType": 0, // "windowIntervalMs": 1000 }, // 流控效果(支持快速失敗和勻速排隊模式) "controlBehavior": 0, // "limitApp": "default", // "maxQueueingTimeMs": 0, // 高級選項 "paramFlowItemList": [ { // 參數類型 "classType": "int", // 限流閾值 "count": 222, // 參數值 "object": "2" } ] }]
負值表示沒有閾值檢查。不需要刪除參數
[ { // RT "avgRt": 1, // CPU 使用率 "highestCpuUsage": -1, // LOAD "highestSystemLoad": -1, // 線程數 "maxThread": -1, // 入口 QPS "qps": -1 }]
[ { // 資源名 "resource": "sentinel_spring_web_context", // 流控應用 "limitApp": "/test", // 授權類型(0代表白名單;1代表黑名單。) "strategy": 0 }]
注意:對于上述JOSN中的一些可選屬性不需要的時候可以刪除。
官方文檔:https://github.com/alibaba/Sentinel/wiki/%E5%9C%A8%E7%94%9F%E4%BA%A7%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Sentinel
sentinel默認的持久化只能從nacos推送到sentinel控制臺,但是實際生產中肯定是雙向修改都能推送的,這個如何解決呢?
其實sentinel官方文檔就有說到解決方法,不過需要自己修改sentinel控制臺的源碼來實現。
這個還是比較復雜的,sentinel只幫我們實現了流控規則的demo,其他的還是要自己修改,這點不太人性化....
在這之前需要自己下載對應版本的sentinel控制臺的源碼,地址:https://github.com/alibaba/Sentinel/tags
在源碼的test目錄下有sentinel提供的demo,分別有apollo、nacos、zookeeper,如下圖:
圖片
這里我們是Nacos,因此只需要nacos包下面的demo。修改步驟如下:
這個sentinel-datasource-nacos依賴默認是<scope>test</scope>,因此我們需要去掉這個,如下:
<!-- for Nacos rule publisher sample --><dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId></dependency>
如果你集成的zookeeper或者apollo,則把相應的依賴也要修改。
將這個nacos包復制到com.alibaba.csp.sentinel.dashboard.rule這個包下,如下圖:
圖片
com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2這個是sentinel提供的demo,只需要將其中的代碼全部覆蓋到com.alibaba.csp.sentinel.dashboard.controller.FlowControllerV1中。
直接覆蓋掉當然不行,還要做一些修改,如下:
@Autowired //使用nacos的依賴 @Qualifier("flowRuleNacosProvider") private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider; @Autowired //使用nacos的依賴 @Qualifier("flowRuleNacosPublisher") private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil這個工具類中對應的是限流規則在nacos中的一些配置項,有groupId、dataId...對應的配置如下:
圖片
需要兩邊統一,可以自己修改。
com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfig這個類中有個方法如下圖:
圖片
默認指定的nacos地址是本地的,這個需要修改。
以上步驟已經改造了sentinel控制臺的流控規則,打包啟動控制臺代碼,命令如下:
mvn clean install -DskipTests=true -pl sentinel-dashboard -am
啟動后在控制臺添加流控規則,可以看到也會同步推送到nacos,包括增刪改。
其他規則修改也很簡單,照葫蘆畫瓢,這里就不再詳細說了,后面會單獨出一篇文章詳細說一下。
首先一個簡單的問題:為什么需要集群流控?單機流控不香嗎?原因如下:
那么如何解決上述的問題呢?sentinel為我們提供了集群流控的規則。思想很簡單就是提供一個專門的server來統計調用的總量,其他的實例都與server保持通信。
集群流控可以精確地控制整個集群的調用總量,結合單機限流兜底,可以更好地發揮流量控制的效果。
集群流控中共有兩種身份:
sentinel的集群限流有兩種模式,分別如下:
下面就以嵌入模式為例介紹一下如何配置。
就以sentinel-openfeign-provider9009這個模塊作為演示,直接啟動三個集群,端口分別為9009、9011、9013,如下圖:
圖片
啟動成功,在sentinel控制臺將會看到有三個實例已經被監控了,如下圖:
圖片
此時只需要在控制臺指定一個服務為token server,其他的為token client,集群流控->新增token server,操作如下圖:
圖片
選取一個作為服務端,另外兩個作為客戶端,此時就已經配置好了,如下圖:
圖片
此時就可以添加集群流控規則了,可以在sentinel控制臺直接添加,也可以通過Nacos直接配置,下圖是通過Nacos配置的,如下圖:
圖片
Nacos推送成功后將會在sentinel控制臺看到這條流控規則的配置,如下圖:
圖片
OK,至此集群流控到這兒就介紹完了,配置好之后可以自己試一下效果,陳某就不再演示了。
官方文檔:https://github.com/alibaba/Sentinel/wiki/%E9%9B%86%E7%BE%A4%E6%B5%81%E6%8E%A7
這一塊內容在后續介紹到網關的時候會詳細講,這里就不再細說了,有想要了解的可以看官方文檔。
官方文檔:https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81
本文鏈接:http://www.www897cc.com/showinfo-26-112744-0.html阿里限流神器 Sentinel 17 問?
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com