隨著微服務的流行,服務和服務之間的穩定性變得越來越重要。Sentinel 是面向分布式、多語言異構化服務架構的流量治理組件,主要以 流量
為切入點,從流量路由、流量控制、流量整形、熔斷降級、系統自適應過載保護、熱點流量防護等多個維度來幫助開發者保障微服務的穩定性。
Sentinel是分布式系統的防御系統。
Sentinel 具有以下特征:
?豐富的應用場景:Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的范圍)、消息削峰填谷、集群流量控制、實時熔斷下游不可用應用等。
?完備的實時監控:Sentinel 同時提供實時的監控功能。您可以在控制臺中看到接入應用的單臺機器秒級數據,甚至 500 臺以下規模的集群的匯總運行情況。
?廣泛的開源生態:Sentinel 提供開箱即用的與其它開源框架/庫的整合模塊,例如與 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相應的依賴并進行簡單的配置即可快速地接入 Sentinel。
?完善的 SPI 擴展點:Sentinel 提供簡單易用、完善的 SPI 擴展接口。您可以通過實現擴展接口來快速地定制邏輯。例如定制規則管理、適配動態數據源等。
1、微服務整合Sentinel
在order-service中整合sentinel,并連接sentinel的控制臺,步驟如下:
1)引入sentinel依賴
<!--sentinel-->
<dependency><groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2)配置控制臺
修改application.yaml文件,添加下面內容:
server:port: 8088
spring:cloud: sentinel:transport:dashboard: localhost:8080
3)訪問order-service的任意端點
打開瀏覽器,訪問http://localhost:8088/order/101,這樣才能觸發sentinel的監控。
然后再訪問sentinel的控制臺,查看效果:
2、流量控制
2.1 簇點鏈路
當請求進入微服務時,首先會訪問DispatcherServlet,然后進入Controller、Service、Mapper,這樣的一個調用鏈就叫做簇點鏈路。簇點鏈路中被監控的每一個接口就是一個資源。
默認情況下sentinel會監控SpringMVC的每一個端點(Endpoint,也就是controller中的方法),因此SpringMVC的每一個端點(Endpoint)就是調用鏈路中的一個資源。
訪問的order-service中的OrderController中的端點:/order/{orderId}
流控、熔斷等都是針對簇點鏈路中的資源來設置的,因此我們可以點擊對應資源后面的按鈕來設置規則:
- 流控:流量控制
- 降級:降級熔斷
- 熱點:熱點參數限流,是限流的一種
- 授權:請求的權限控制
2.2 流控模式
在添加限流規則時,點擊高級選項,可以選擇三種流控模式:
- 直接:統計當前資源的請求,觸發閾值時對當前資源直接限流,也是默認的模式
- 關聯:統計與當前資源相關的另一個資源,觸發閾值時,對當前資源限流
- 鏈路:統計從指定鏈路訪問到本資源的請求,觸發閾值時,對指定鏈路限流
2.2.1 關聯模式
關聯模式:統計與當前資源相關的另一個資源,觸發閾值時,對當前資源限流
配置規則:
語法說明:當/write資源訪問量觸發閾值時,就會對/read資源限流,避免影響/write資源。
使用場景:比如用戶支付時需要修改訂單狀態,同時用戶要查詢訂單。查詢和修改操作會爭搶數據庫鎖,產生競爭。業務需求是優先支付和更新訂單的業務,因此當修改訂單業務觸發閾值時,需要對查詢訂單業務限流。
需求說明:
-
在OrderController新建兩個端點:/order/query和/order/update,無需實現業務
-
配置流控規則,當/order/ update資源被訪問的QPS超過5時,對/order/query請求限流
1)定義/order/query端點,模擬訂單查詢
@GetMapping("/query")
public String queryOrder() {return "查詢訂單成功";
}
2)定義/order/update端點,模擬訂單更新
@GetMapping("/update")
public String updateOrder() {return "更新訂單成功";
}
重啟服務,查看sentinel控制臺的簇點鏈路:
3)配置流控規則
對哪個端點限流,就點擊哪個端點后面的按鈕。我們是對訂單查詢/order/query限流,因此點擊它后面的按鈕:
在表單中填寫流控規則:
4)在Jmeter測試
選擇《流控模式-關聯》:
可以看到1000個用戶,100秒,因此QPS為10,超過了我們設定的閾值:5
查看http請求:
請求的目標是/order/update,這樣這個斷點就會觸發閾值。
但限流的目標是/order/query,我們在瀏覽器訪問,可以發現:
確實被限流了。
5)總結
2.2.2 鏈路模式
鏈路模式:只針對從指定鏈路訪問到本資源的請求做統計,判斷是否超過閾值。
配置示例:
例如有兩條請求鏈路:
-
/test1 --> /common
-
/test2 --> /common
如果只希望統計從/test2進入到/common的請求,則可以這樣配置:
實戰案例
需求:有查詢訂單和創建訂單業務,兩者都需要查詢商品。針對從查詢訂單進入到查詢商品的請求統計,并設置限流。
步驟:
-
在OrderService中添加一個queryGoods方法,不用實現業務
-
在OrderController中,改造/order/query端點,調用OrderService中的queryGoods方法
-
在OrderController中添加一個/order/save的端點,調用OrderService的queryGoods方法
-
給queryGoods設置限流規則,從/order/query進入queryGoods的方法限制QPS必須小于2
實現:
1)添加查詢商品方法
在order-service服務中,給OrderService類添加一個queryGoods方法:
public void queryGoods(){System.err.println("查詢商品");
}
2)查詢訂單時,查詢商品
在order-service的OrderController中,修改/order/query端點的業務邏輯:
@GetMapping("/query")
public String queryOrder() {// 查詢商品orderService.queryGoods();// 查詢訂單System.out.println("查詢訂單");return "查詢訂單成功";
}
3)新增訂單,查詢商品
在order-service的OrderController中,修改/order/save端點,模擬新增訂單:
@GetMapping("/save")
public String saveOrder() {// 查詢商品orderService.queryGoods();// 查詢訂單System.err.println("新增訂單");return "新增訂單成功";
}
4)給查詢商品添加資源標記
默認情況下,OrderService中的方法是不被Sentinel監控的,需要我們自己通過注解來標記要監控的方法。
給OrderService的queryGoods方法添加@SentinelResource注解:
@SentinelResource("goods")
public void queryGoods(){System.err.println("查詢商品");
}
鏈路模式中,是對不同來源的兩個鏈路做監控。但是sentinel默認會給進入SpringMVC的所有請求設置同一個root資源,會導致鏈路模式失效。
我們需要關閉這種對SpringMVC的資源聚合,修改order-service服務的application.yml文件:
spring:cloud:sentinel:web-context-unify: false # 關閉context整合
重啟服務,訪問/order/query和/order/save,可以查看到sentinel的簇點鏈路規則中,出現了新的資源:
5)添加流控規則
點擊goods資源后面的流控按鈕,在彈出的表單中填寫下面信息:
只統計從/order/query進入/goods的資源,QPS閾值為2,超出則被限流。
6)Jmeter測試
選擇《流控模式-鏈路》:
可以看到這里200個用戶,50秒內發完,QPS為4,超過了我們設定的閾值2
一個http請求是訪問/order/save:
運行的結果:
完全不受影響。
另一個是訪問/order/query:
運行結果:
每次只有2個通過。
2.2.3 總結
流控模式有哪些?
?直接:對當前資源限流
?關聯:高優先級資源觸發閾值,對低優先級資源限流。
?鏈路:閾值統計時,只統計從指定資源進入當前資源的請求,是對請求來源的限流
2.3 流控效果
在流控的高級選項中,還有一個流控效果選項:
流控效果是指請求達到流控閾值時應該采取的措施,包括三種:
-
快速失敗:達到閾值后,新的請求會被立即拒絕并拋出FlowException異常。是默認的處理方式。
-
warm up:預熱模式,對超出閾值的請求同樣是拒絕并拋出異常。但這種模式閾值會動態變化,從一個較小值逐漸增加到最大閾值。
-
排隊等待:讓所有的請求按照先后次序排隊執行,兩個請求的間隔不能小于指定時長
2.3.1 warm up
閾值一般是一個微服務能承擔的最大QPS,但是一個服務剛剛啟動時,一切資源尚未初始化(冷啟動),如果直接將QPS跑到最大值,可能導致服務瞬間宕機。
warm up也叫預熱模式,是應對服務冷啟動的一種方案。請求閾值初始值是 maxThreshold / coldFactor,持續指定時長后,逐漸提高到maxThreshold值。而coldFactor的默認值是3.
例如,我設置QPS的maxThreshold為10,預熱時間為5秒,那么初始閾值就是 10 / 3 ,也就是3,然后在5秒后逐漸增長到10.
案例
需求:給/order/{orderId}這個資源設置限流,最大QPS為10,利用warm up效果,預熱時長為5秒
1)配置流控規則:
2)Jmeter測試
選擇《流控效果,warm up》:
QPS為10.
剛剛啟動時,大部分請求失敗,成功的只有3個,說明QPS被限定在3:
隨著時間推移,成功比例越來越高:
到Sentinel控制臺查看實時監控:
一段時間后:
2.3.2 排隊等待
當請求超過QPS閾值時,快速失敗和warm up 會拒絕新的請求并拋出異常。
而排隊等待則是讓所有請求進入一個隊列中,然后按照閾值允許的時間間隔依次執行。后來的請求必須等待前面執行完成,如果請求預期的等待時間超出最大時長,則會被拒絕。
工作原理
例如:QPS = 5,意味著每200ms處理一個隊列中的請求;timeout = 2000,意味著預期等待時長超過2000ms的請求會被拒絕并拋出異常。
那什么叫做預期等待時長呢?
比如現在一下子來了12 個請求,因為每200ms執行一個請求,那么:
- 第6個請求的預期等待時長 = 200 * (6 - 1) = 1000ms
- 第12個請求的預期等待時長 = 200 * (12-1) = 2200ms
現在,第1秒同時接收到10個請求,但第2秒只有1個請求,此時QPS的曲線這樣的:
如果使用隊列模式做流控,所有進入的請求都要排隊,以固定的200ms的間隔執行,QPS會變的很平滑: