初識Sentinel

? ? ? ?

目錄

1.解決雪崩的方式有4種:

1.1.2超時處理:

1.1.3倉壁模式

1.1.4.斷路器

1.1.5.限流

1.1.6.總結

1.2.服務保護技術對比

1.3.Sentinel介紹和安裝

1.3.1.初識Sentinel

1.3.2.安裝Sentinel

1.4.微服務整合Sentinel

2.流量控制

2.1.簇點鏈路

2.1.快速入門

2.1.1.示例

2.1.2.練習:

2.2.流控模式

2.2.1.關聯模式

2.2.2.鏈路模式

1)添加查詢商品方法

2)查詢訂單時,查詢商品

3)新增訂單,查詢商品

4)給查詢商品添加資源標記

5)添加流控規則

6)Jmeter測試

2.2.3.總結

2.3.流控效果

2.3.1.warm up

1)配置流控規則:

2)Jmeter測試

2.3.2.排隊等待

1)添加流控規則

2)Jmeter測試

2.3.3.總結

2.4.熱點參數限流

2.4.1.全局參數限流

2.4.2.熱點參數限流

2.4.4.案例

1)標記資源

2)熱點參數限流規則

3)Jmeter測試

3.隔離和降級

3.1.FeignClient整合Sentinel

3.1.1.修改配置,開啟sentinel功能

3.1.2.編寫失敗降級邏輯

3.1.3.總結

3.2.線程隔離(艙壁模式)

3.2.1.線程隔離的實現方式

3.2.2.sentinel的線程隔離

1)配置隔離規則

2)Jmeter測試

3.2.3.總結

3.3.熔斷降級

3.3.1.慢調用

1)設置慢調用

2)設置熔斷規則

3)測試

3.3.2.異常比例、異常數

1)設置異常請求

2)設置熔斷規則

3)測試

4.授權規則

4.1.授權規則

4.1.1.基本規則

4.1.2.如何獲取origin

4.1.3.給網關添加請求頭

4.1.4.配置授權規則

4.2.自定義異常結果

4.2.1.異常類型

4.2.2.自定義異常處理

5.規則持久化

5.1.規則管理模式

5.1.1.pull模式

5.1.2.push模式

5.2.實現push模式

一、修改order-service服務

1.引入依賴

2.配置nacos地址

二、修改sentinel-dashboard源碼

1. 解壓

2. 修改nacos依賴

3. 添加nacos支持

4. 修改nacos地址

5. 配置nacos數據源

6. 修改前端頁面

7. 重新編譯、打包項目

8.啟動


? ? ? ?在微服務中,服務間調用關系錯綜復雜,一個微服務往往依賴于多個其他微服務,假如服務I提供者發生故障,當前的應用的部分業務因為依賴服務I,因此而被阻塞,此時,其他不依賴于服務I幾乎不受影響,但是當依賴于服務I的請求不會被響應,導致該tomcat的這個線程不會釋放,于是越來越多的用戶請求到來,越來越多的線程會被阻塞,服務器支持的線程和并發數有限,請求一直阻塞,會導致服務器資源耗盡,從而導致所有其他服務都不可用,那么當前服務也不可用了,那么依賴于當前服務的其他服務隨著時間的推移,最終也都會變的不可用,形成級聯失敗,雪崩就發生了

1.解決雪崩的方式有4種:

1.1.2超時處理:

設定超時時間,請求超過一定的時間沒有響應就返回錯誤信息,不會無休止的等待

1.1.3倉壁模式

倉壁模式來源于船艙的設計:

? ? ? ?于此類似,我們可以限定每個業務能使用的線程數,避免耗盡整個tomcat資源,因此也叫作線程隔離

1.1.4.斷路器

斷路器模式:由斷路器統計業務執行的異常比例,如果超出閾值則會熔斷該業務,攔截訪問該業務的一切請求。

斷路器會統計訪問某個服務的請求數量,異常比例:

當發現訪問服務D的請求異常比例過高時,認為服務D有導致雪崩的風險,會攔截訪問服務D的一切請求,形成熔斷:

1.1.5.限流

流量控制:限制業務訪問的QPS,避免服務因流量的突增而故障。

1.1.6.總結

什么是雪崩問題?

  • 微服務之間相互調用,因為調用鏈中的一個服務故障,引起整個鏈路都無法訪問的情況。

可以認為:

? ? ? 限流是對服務的保護,避免因瞬間高并發流量而導致服務故障,進而避免雪崩。是一種預防措施。

? ? ? 超時處理、線程隔離、降級熔斷是在部分服務故障時,將故障控制在一定范圍,避免雪崩。是一種補救措施。

1.2.服務保護技術對比

在SpringCloud當中支持多種服務保護技術:

  • Netfix Hystrix

  • Sentinel

  • Resilience4J

? ? ? ?早期比較流行的是Hystrix框架,但目前國內實用最廣泛的還是阿里巴巴的Sentinel框架,這里我們做下對比:

SentinelHystrix
隔離策略信號量隔離線程池隔離/信號量隔離
熔斷降級策略基于慢調用比例或異常比例基于失敗比率
實時指標實現滑動窗口滑動窗口(基于 RxJava)
規則配置支持多種數據源支持多種數據源
擴展性多個擴展點插件的形式
基于注解的支持支持支持
限流基于 QPS,支持基于調用關系的限流有限的支持
流量整形支持慢啟動、勻速排隊模式不支持
系統自適應保護支持不支持
控制臺開箱即用,可配置規則、查看秒級監控、機器發現等不完善
常見框架的適配Servlet、Spring Cloud、Dubbo、gRPC 等Servlet、Spring Cloud Netflix

1.3.Sentinel介紹和安裝p

1.3.1.初識Sentinel

Sentinel是阿里巴巴開源的一款微服務流量控制組件。官網地址:home | Sentinel

Sentinel 具有以下特征:

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

1.3.2.安裝Sentinel

1)下載

sentinel官方提供了UI控制臺,方便我們對系統做限流設置。大家可以在GitHub下載?

2)運行

將jar包放到任意非中文目錄,執行命令:

java -jar sentinel-dashboard-1.8.1.jar

如果要修改Sentinel的默認端口、賬戶、密碼,可以通過下列配置:

配置項默認值說明
server.port8080服務端口
sentinel.dashboard.auth.usernamesentinel默認用戶名
sentinel.dashboard.auth.passwordsentinel默認密碼

例如,修改端口:

java -Dserver.port=8090 -jar sentinel-dashboard-1.8.1.jar

3)訪問

訪問http://localhost:8080頁面,就可以看到sentinel的控制臺了:

需要輸入賬號和密碼,默認都是:sentinel

登錄后,發現一片空白,什么都沒有:

這是因為我們還沒有與微服務整合。

1.4.微服務整合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.1.快速入門

2.1.1.示例

點擊資源/order/{orderId}后面的流控按鈕,就可以彈出表單。

表單中可以填寫限流規則,如下:

? ? ? ?其含義是限制 /order/{orderId}這個資源的單機QPS為1,即每秒只允許1次請求,超出的請求會被攔截并報錯。

2.1.2.練習:

需求:給 /order/{orderId}這個資源設置流控規則,QPS不能超過 5,然后測試。

1)首先在sentinel控制臺添加限流規則

2)利用jmeter測試

選擇:

20個用戶,2秒內運行完,QPS是10,超過了5.

選中流控入門,QPS<5右鍵運行:

注意,不要點擊菜單中的執行按鈕來運行。?

結果:

可以看到,成功的請求每次只有5個

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的請求,則可以這樣配置:

實戰案例

需求:有查詢訂單和創建訂單業務,兩者都需要查詢商品。針對從查詢訂單進入到查詢商品的請求統計,并設置限流。

步驟:

  1. 在OrderService中添加一個queryGoods方法,不用實現業務

  2. 在OrderController中,改造/order/query端點,調用OrderService中的queryGoods方法

  3. 在OrderController中添加一個/order/save的端點,調用OrderService的queryGoods方法

  4. 給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會變的很平滑:

平滑的QPS曲線,對于服務器來說是更友好的。

案例

需求:給/order/{orderId}這個資源設置限流,最大QPS為10,利用排隊的流控效果,超時時長設置為5s

1)添加流控規則

2)Jmeter測試

選擇《流控效果,隊列》:

QPS為15,已經超過了我們設定的10。

如果是之前的 快速失敗、warmup模式,超出的請求應該會直接報錯。

但是我們看看隊列模式的運行結果:

全部都通過了。

再去sentinel查看實時監控的QPS曲線:

? ? ? ? ?QPS非常平滑,一致保持在10,但是超出的請求沒有被拒絕,而是放入隊列。因此響應時間(等待時間)會越來越長。

當隊列滿了以后,才會有部分請求失敗:

2.3.3.總結

流控效果有哪些?

  • 快速失敗:QPS超過閾值時,拒絕新的請求

  • warm up: QPS超過閾值時,拒絕新的請求;QPS閾值是逐漸提升的,可以避免冷啟動時高并發導致服務宕機。

  • 排隊等待:請求會進入隊列,按照閾值允許的時間間隔依次執行請求;如果請求預期等待時長大于超時時間,直接拒絕

2.4.熱點參數限流

? ? ? ?之前的限流是統計訪問某個資源的所有請求,判斷是否超過QPS閾值。而熱點參數限流是分別統計參數值相同的請求,判斷是否超過QPS閾值。

2.4.1.全局參數限流

例如,一個根據id查詢商品的接口:

? ? ? ?訪問/goods/{id}的請求中,id參數值會有變化,熱點參數限流會根據參數值分別統計QPS,統計結果:

當id=1的請求觸發閾值被限流時,id值不為1的請求不受影響。

配置示例:

? ? ? ?代表的含義是:對hot這個資源的0號參數(第一個參數)做統計,每1秒相同參數值的請求數不能超過5

2.4.2.熱點參數限流

剛才的配置中,對查詢商品這個接口的所有商品一視同仁,QPS都限定為5.

? ? ? ?而在實際開發中,可能部分商品是熱點商品,例如秒殺商品,我們希望這部分商品的QPS限制與其它商品不一樣,高一些。那就需要配置熱點參數限流的高級選項了:

? ? ? ?結合上一個配置,這里的含義是對0號的long類型參數限流,每1秒相同參數的QPS不能超過5,有兩個例外:

  • 如果參數值是100,則每1秒允許的QPS為10
  • 如果參數值是101,則每1秒允許的QPS為152.4.4.案例

案例需求:給/order/{orderId}這個資源添加熱點參數限流,規則如下:

  • 默認的熱點參數規則是每1秒請求量不超過2
  • 給102這個參數設置例外:每1秒請求量不超過4
  • 給103這個參數設置例外:每1秒請求量不超過10

注意事項:熱點參數限流對默認的SpringMVC資源無效,需要利用@SentinelResource注解標記資源

1)標記資源

給order-service中的OrderController中的/order/{orderId}資源添加注解:

2)熱點參數限流規則

訪問該接口,可以看到我們標記的hot資源出現了:

這里不要點擊hot后面的按鈕,頁面有BUG

點擊左側菜單中熱點規則菜單:

點擊新增,填寫表單:

?

3)Jmeter測試

選擇《熱點參數限流 QPS1》:

這里發起請求的QPS為5.

包含3個http請求:

普通參數,QPS閾值為2

運行結果:

例外項,QPS閾值為4

運行結果:

例外項,QPS閾值為10

運行結果:

3.隔離和降級

? ? ? ?限流是一種預防措施,雖然限流可以盡量避免因高并發而引起的服務故障,但服務還會因為其它原因而故障。

而要將這些故障控制在一定范圍,避免雪崩,就要靠線程隔離(艙壁模式)和熔斷降級手段了。

? ? ? ?線程隔離之前講到過:調用者在調用服務提供者時,給每個調用的請求分配獨立線程池,出現故障時,最多消耗這個線程池內資源,避免把調用者的所有資源耗盡。

熔斷降級:是在調用方這邊加入斷路器,統計對服務提供者的調用,如果調用的失敗比例過高,則熔斷該業務,不允許訪問該服務的提供者了。

? ? ? ?可以看到,不管是線程隔離還是熔斷降級,都是對客戶端(調用方)的保護。需要在調用方 發起遠程調用時做線程隔離、或者服務熔斷。

? ? ? ? 而我們的微服務遠程調用都是基于Feign來完成的,因此我們需要將Feign與Sentinel整合,在Feign里面實現線程隔離和服務熔斷。

3.1.FeignClient整合Sentinel

SpringCloud中,微服務調用都是通過Feign來實現的,因此做客戶端保護必須整合Feign和Sentinel。

3.1.1.修改配置,開啟sentinel功能

修改OrderService的application.yml文件,開啟Feign的Sentinel功能:

feign:sentinel:enabled: true # 開啟feign對sentinel的支持

3.1.2.編寫失敗降級邏輯

? ? ? ?業務失敗后,不能直接報錯,而應該返回用戶一個友好提示或者默認結果,這個就是失敗降級邏輯。

給FeignClient編寫失敗后的降級邏輯

①方式一:FallbackClass,無法對遠程調用的異常做處理

②方式二:FallbackFactory,可以對遠程調用的異常做處理,我們選擇這種

這里我們演示方式二的失敗降級處理。

步驟一:在feing-api項目中定義類,實現FallbackFactory:

代碼:

package cn.itcast.feign.clients.fallback;
?
import cn.itcast.feign.clients.UserClient;
import cn.itcast.feign.pojo.User;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
?
@Slf4j
public class UserClientFallbackFactory implements FallbackFactory<UserClient> {@Overridepublic UserClient create(Throwable throwable) {return new UserClient() {@Overridepublic User findById(Long id) {log.error("查詢用戶異常", throwable);return new User();}};}
}
?步驟二:在feing-api項目中的DefaultFeignConfiguration類中將UserClientFallbackFactory注冊為一個Bean:
@Bean
public UserClientFallbackFactory userClientFallbackFactory(){return new UserClientFallbackFactory();
}

步驟三:在feing-api項目中的UserClient接口中使用UserClientFallbackFactory:

import cn.itcast.feign.clients.fallback.UserClientFallbackFactory;
import cn.itcast.feign.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
?
@FeignClient(value = "userservice", fallbackFactory = UserClientFallbackFactory.class)
public interface UserClient {
?@GetMapping("/user/{id}")User findById(@PathVariable("id") Long id);
}

重啟后,訪問一次訂單查詢業務,然后查看sentinel控制臺,可以看到新的簇點鏈路:

3.1.3.總結

Sentinel支持的雪崩解決方案:

  • 線程隔離(倉壁模式)

  • 降級熔斷

Feign整合Sentinel的步驟:

  • 在application.yml中配置:feign.sentienl.enable=true

  • 給FeignClient編寫FallbackFactory并注冊為Bean

  • 將FallbackFactory配置到FeignClient

3.2.線程隔離(艙壁模式)

3.2.1.線程隔離的實現方式

線程隔離有兩種方式實現:

  • 線程池隔離

  • 信號量隔離(Sentinel默認采用)

如圖:

線程池隔離:給每個服務調用業務分配一個線程池,利用線程池本身實現隔離效果

信號量隔離:不創建線程池,而是計數器模式,記錄業務使用的線程數量,達到信號量上限時,禁止新的請求。

兩者的優缺點:

3.2.2.sentinel的線程隔離

用法說明

在添加限流規則時,可以選擇兩種閾值類型:

  • QPS:就是每秒的請求數,在快速入門中已經演示過

  • 線程數:是該資源能使用用的tomcat線程數的最大值。也就是通過限制線程數量,實現線程隔離(艙壁模式)。

案例需求:給 order-service服務中的UserClient的查詢用戶接口設置流控規則,線程數不能超過 2。然后利用jemeter測試。

1)配置隔離規則

選擇feign接口后面的流控按鈕:

填寫表單:

2)Jmeter測試

選擇《閾值類型-線程數<2》:

一次發生10個請求,有較大概率并發線程數超過2,而超出的請求會走之前定義的失敗降級邏輯。

查看運行結果:

發現雖然結果都是通過了,不過部分請求得到的響應是降級返回的null信息。

3.2.3.總結

線程隔離的兩種手段是?

  • 信號量隔離

  • 線程池隔離

信號量隔離的特點是?

  • 基于計數器模式,簡單,開銷小

線程池隔離的特點是?

  • 基于線程池模式,有額外開銷,但隔離控制更強

3.3.熔斷降級

? ? ? ?熔斷降級是解決雪崩問題的重要手段。其思路是由斷路器統計服務調用的異常比例、慢請求比例,如果超出閾值則會熔斷該服務。即攔截訪問該服務的一切請求;而當服務恢復時,斷路器會放行訪問該服務的請求。

斷路器控制熔斷和放行是通過狀態機來完成的:

狀態機包括三個狀態:

  • closed:關閉狀態,斷路器放行所有請求,并開始統計異常比例、慢請求比例。超過閾值則切換到open狀態

  • open:打開狀態,服務調用被熔斷,訪問被熔斷服務的請求會被拒絕,快速失敗,直接走降級邏輯。Open狀態5秒后會進入half-open狀態

  • half-open:半開狀態,放行一次請求,根據執行結果來判斷接下來的操作。

    • 請求成功:則切換到closed狀態

    • 請求失敗:則切換到open狀態

斷路器熔斷策略有三種:慢調用、異常比例、異常數

3.3.1.慢調用

慢調用:業務的響應時長(RT)大于指定時長的請求認定為慢調用請求。在指定時間內,如果請求數量超過設定的最小數量,慢調用比例大于設定的閾值,則觸發熔斷。

例如:

解讀:RT超過500ms的調用是慢調用,統計最近10000ms內的請求,如果請求量超過10次,并且慢調用比例不低于0.5,則觸發熔斷,熔斷時長為5秒。然后進入half-open狀態,放行一次請求做測試。

案例

需求:給 UserClient的查詢用戶接口設置降級規則,慢調用的RT閾值為50ms,統計時間為1秒,最小請求數量為5,失敗閾值比例為0.4,熔斷時長為5

1)設置慢調用

修改user-service中的/user/{id}這個接口的業務。通過休眠模擬一個延遲時間:

此時,orderId=101的訂單,關聯的是id為1的用戶,調用時長為60ms:

orderId=102的訂單,關聯的是id為2的用戶,調用時長為非常短;

2)設置熔斷規則

下面,給feign接口設置降級規則:

規則:

超過50ms的請求都會被認為是慢請求

3)測試

在瀏覽器訪問:http://localhost:8088/order/101,快速刷新5次,可以發現:

觸發了熔斷,請求時長縮短至5ms,快速失敗了,并且走降級邏輯,返回的null

在瀏覽器訪問:http://localhost:8088/order/102,竟然也被熔斷了:

3.3.2.異常比例、異常數

異常比例或異常數:統計指定時間內的調用,如果調用次數超過指定請求數,并且出現異常的比例達到設定的比例閾值(或超過指定異常數),則觸發熔斷。

例如,一個異常比例設置:

解讀:統計最近1000ms內的請求,如果請求量超過10次,并且異常比例不低于0.4,則觸發熔斷。

一個異常數設置:

解讀:統計最近1000ms內的請求,如果請求量超過10次,并且異常比例不低于2次,則觸發熔斷。

案例

需求:給 UserClient的查詢用戶接口設置降級規則,統計時間為1秒,最小請求數量為5,失敗閾值比例為0.4,熔斷時長為5s

1)設置異常請求

首先,修改user-service中的/user/{id}這個接口的業務。手動拋出異常,以觸發異常比例的熔斷:

也就是說,id 為 2時,就會觸發異常

2)設置熔斷規則

下面,給feign接口設置降級規則:

規則:

在5次請求中,只要異常比例超過0.4,也就是有2次以上的異常,就會觸發熔斷。

3)測試

在瀏覽器快速訪問:http://localhost:8088/order/102,快速刷新5次,觸發熔斷:

此時,我們去訪問本來應該正常的103:

4.授權規則

授權規則可以對請求方來源做判斷和控制。

4.1.授權規則

4.1.1.基本規則

授權規則可以對調用方的來源做控制,有白名單和黑名單兩種方式。

  • 白名單:來源(origin)在白名單內的調用者允許訪問

  • 黑名單:來源(origin)在黑名單內的調用者不允許訪問

點擊左側菜單的授權,可以看到授權規則:

  • 資源名:就是受保護的資源,例如/order/{orderId}

  • 流控應用:是來源者的名單,

    • 如果是勾選白名單,則名單中的來源被許可訪問。

    • 如果是勾選黑名單,則名單中的來源被禁止訪問。

比如:

? ? ? ?我們允許請求從gateway到order-service,不允許瀏覽器訪問order-service,那么白名單中就要填寫網關的來源名稱(origin)

4.1.2.如何獲取origin

Sentinel是通過RequestOriginParser這個接口的parseOrigin來獲取請求的來源的。

public interface RequestOriginParser {/*** 從請求request對象中獲取origin,獲取方式自定義*/String parseOrigin(HttpServletRequest request);
}

這個方法的作用就是從request對象中,獲取請求者的origin值并返回。

? ? ? ?默認情況下,sentinel不管請求者從哪里來,返回值永遠是default,也就是說一切請求的來源都被認為是一樣的值default。

因此,我們需要自定義這個接口的實現,讓不同的請求,返回不同的origin

例如order-service服務中,我們定義一個RequestOriginParser的實現類:

package cn.itcast.order.sentinel;
?
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
?
import javax.servlet.http.HttpServletRequest;
?
@Component
public class HeaderOriginParser implements RequestOriginParser {@Overridepublic String parseOrigin(HttpServletRequest request) {// 1.獲取請求頭String origin = request.getHeader("origin");// 2.非空判斷if (StringUtils.isEmpty(origin)) {origin = "blank";}return origin;}
}

我們會嘗試從request-header中獲取origin值。

4.1.3.給網關添加請求頭

? ? ? ?既然獲取請求origin的方式是從reques-header中獲取origin值,我們必須讓所有從gateway路由到微服務的請求都帶上origin頭

這個需要利用之前學習的一個GatewayFilter來實現,AddRequestHeaderGatewayFilter。

修改gateway服務中的application.yml,添加一個defaultFilter:

spring:cloud:gateway:default-filters:- AddRequestHeader=origin,gatewayroutes:# ...略

? ? ? ?這樣,從gateway路由的所有請求都會帶上origin頭,值為gateway。而從其它地方到達微服務的請求則沒有這個頭。

4.1.4.配置授權規則

接下來,我們添加一個授權規則,放行origin值為gateway的請求。

配置如下:

現在,我們直接跳過網關,訪問order-service服務:

通過網關訪問:

4.2.自定義異常結果

默認情況下,發生限流、降級、授權攔截時,都會拋出異常到調用方。異常結果都是flow limmiting(限流)。這樣不夠友好,無法得知是限流還是降級還是授權攔截。

4.2.1.異常類型

而如果要自定義異常時的返回結果,需要實現BlockExceptionHandler接口:

public interface BlockExceptionHandler {/*** 處理請求被限流、降級、授權攔截時拋出的異常:BlockException*/void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception;
}

這個方法有三個參數:

  • HttpServletRequest request:request對象

  • HttpServletResponse response:response對象

  • BlockException e:被sentinel攔截時拋出的異常

這里的BlockException包含多個不同的子類:

異常說明
FlowException限流異常
ParamFlowException熱點參數限流的異常
DegradeException降級異常
AuthorityException授權規則異常
SystemBlockException系統規則異常

4.2.2.自定義異常處理

下面,我們就在order-service定義一個自定義異常處理類:

package cn.itcast.order.sentinel;
?
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import org.springframework.stereotype.Component;
?
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
?
@Component
public class SentinelExceptionHandler implements BlockExceptionHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {String msg = "未知異常";int status = 429;
?if (e instanceof FlowException) {msg = "請求被限流了";} else if (e instanceof ParamFlowException) {msg = "請求被熱點參數限流";} else if (e instanceof DegradeException) {msg = "請求被降級了";} else if (e instanceof AuthorityException) {msg = "沒有權限訪問";status = 401;}
?response.setContentType("application/json;charset=utf-8");response.setStatus(status);response.getWriter().println("{\"msg\": " + msg + ", \"status\": " + status + "}");}
}

重啟測試,在不同場景下,會返回不同的異常消息.

限流:

授權攔截時:

5.規則持久化

現在,sentinel的所有規則都是內存存儲,重啟后所有規則都會丟失。在生產環境下,我們必須確保這些規則的持久化,避免丟失。

5.1.規則管理模式

規則是否能持久化,取決于規則管理模式,sentinel支持三種規則管理模式:

  • 原始模式:Sentinel的默認模式,將規則保存在內存,重啟服務會丟失。

  • pull模式

  • push模式

5.1.1.pull模式

pull模式:控制臺將配置的規則推送到Sentinel客戶端,而客戶端會將配置規則保存在本地文件或數據庫中。以后會定時去本地文件或數據庫中查詢,更新本地規則。

5.1.2.push模式

push模式:控制臺將配置規則推送到遠程配置中心,例如Nacos。Sentinel客戶端監聽Nacos,獲取配置變更的推送消息,完成本地配置更新。

5.2.實現push模式

一、修改order-service服務

修改OrderService,讓其監聽Nacos中的sentinel規則配置。

具體步驟如下:

1.引入依賴

在order-service中引入sentinel監聽nacos的依賴:

<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

2.配置nacos地址

在order-service中的application.yml文件配置nacos地址及監聽的配置信息:

spring:cloud:sentinel:datasource:flow:nacos:server-addr: localhost:8848 # nacos地址dataId: orderservice-flow-rulesgroupId: SENTINEL_GROUPrule-type: flow # 還可以是:degrade、authority、param-flow

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/40904.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/40904.shtml
英文地址,請注明出處:http://en.pswp.cn/news/40904.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Ubuntu中怎么清空mysql數據

要清空 MySQL 數據&#xff0c;可以使用以下步驟來執行。請注意&#xff0c;這將會永久刪除數據庫中的所有數據&#xff0c;請謹慎操作&#xff0c;并在操作前備份重要數據。 登錄 MySQL&#xff1a; 打開終端&#xff0c;使用以下命令登錄到 MySQL 數據庫。根據情況&#xf…

黑馬項目一階段面試58題 Web14題(一)

一、什么是AJAX 異步的JavaScript和XML。用來做前端和后端的異步請求的技術。 異步請求&#xff1a;只更新部分前端界面的請求&#xff0c;做到局部更新。 比如注冊&#xff0c;提示用戶名已存在而整個頁面沒有動 比如百度圖片搜索美女&#xff0c;進度條越變越短&#xff…

== 和 equals 的對比 [面試題]

和 equals 的對比[面試題] 文章目錄 和 equals 的對比[面試題]1. 和 equals 簡介2. Object 類中 equals() 源碼3. String 類中 equals() 源碼4. Integer 類中 equals() 源碼5. 如何重寫 equals 方法 1. 和 equals 簡介 是一個比較運算符 &#xff1a;既可以判斷基本數據類型…

【數據結構OJ題】鏈表的回文結構

原題鏈接&#xff1a;https://www.nowcoder.com/practice/d281619e4b3e4a60a2cc66ea32855bfa?tpId49&&tqId29370&rp1&ru/activity/oj&qru/ta/2016test/question-ranking 目錄 1. 題目描述 2. 思路分析 3. 代碼實現 1. 題目描述 2. 思路分析 在做這道…

re中的match和search有什么區別?

問題:請說明以下re模塊中的match和search有什么區別? re.match()與re.search()的區別 re.match()只匹配字符串的開始,如果字符串開始不符合正則表達式,則匹配失敗,結果返回None,而re.search()匹配整個字符串,直到找到一個匹配 re.search() re.search()掃描整個字符串并…

老師如何制作二維碼分班查詢系統?技術老師分享的創建框架值得借鑒

作為一名班主任&#xff0c;開學前需要搞定分班問題&#xff0c;可以通過制作一個分班二維碼查詢系統&#xff0c;讓學生和家長可以通過掃描二維碼快速查到自己的分班信息&#xff0c;分享一下我制作的過程&#xff0c;希望對老師們有幫助&#xff08;結尾有驚喜&#xff09;&a…

內網穿透——使用Windows自帶的網站程序建立網站

文章目錄 1.前言2.Windows網頁設置2.1 Windows IIS功能設置2.2 IIS網頁訪問測試 3. Cpolar內網穿透3.1 下載安裝Cpolar3.2 Cpolar云端設置3.3 Cpolar本地設置 4.公網訪問測試5.結語 1.前言 在網上各種教程和介紹中&#xff0c;搭建網頁都會借助各種軟件的幫助&#xff0c;比如…

RP2040開發板自制樹莓派邏輯分析儀

目錄 前言 1 準備工作和前提條件 1.1 Raspberry Pi Pico RP2040板子一個 1.2 Firmware-LogicAnalyzer-5.0.0.0-PICO.uf2固件 1.3 LogicAnalyzer-5.0.0.0-win-x64軟件 2 操作指南 2.1 按住Raspberry Pi Pico開發板的BOOTSEL按鍵&#xff0c;再接上USB接口到電腦 2.2 刷入…

End-to-End Object Detection with Transformers

DERT 目標檢測 基于卷積神經網絡的目標檢測回顧DETR對比Swin Transformer摘要檢測網絡流程DERT網絡架構編碼器概述解碼器概述整體結構object queries的初始化Decoder中的Muiti-Head Self-AttentionDecoder中的Muiti-Head Attention 損失函數解決的問題 基于卷積神經網絡的目標檢…

內網穿透實戰應用——【通過cpolar分享本地電腦上有趣的照片:發布piwigo網頁】

通過cpolar分享本地電腦上有趣的照片&#xff1a;發布piwigo網頁 文章目錄 通過cpolar分享本地電腦上有趣的照片&#xff1a;發布piwigo網頁前言1. 設定一條內網穿透數據隧道2. 與piwigo網站綁定3. 在創建隧道界面填寫關鍵信息4. 隧道創建完成 總結 前言 首先在本地電腦上部署…

Unity - 從PackageManager中安裝內置工具

1.MemoryProfiler 內存分析工具 add from git url &#xff1a;com.unity.memoryprofiler 使用地址記錄&#xff1a;unity3d內存分析工具memory profiler_unity3d memory profile_Marco&GalaxyDragon的博客-CSDN博客 理解Unity Memory Profiler - 知乎

Gradle和Maven的詳細講解和兩者之間的區別

Gradle 詳細介紹 Gradle 是一種基于 Groovy 語言的構建自動化工具&#xff0c;用于構建、測試和部署項目。它使用聲明式的腳本來定義構建過程&#xff0c;允許開發者靈活地配置項目構建。Gradle 使用一種被稱為 Groovy DSL&#xff08;領域特定語言&#xff09;的語法&#xf…

mysql知識點+面試總結

目錄 1 mysql介紹 2 數據庫常見語法 3 數據庫表的常見語法 4 其他常見語法&#xff08;日期&#xff0c;查詢表字段&#xff09; 5 JDBC開發步驟 6 索引 6.1 索引常見語法 7 常見面試總結 8 java代碼搭建監控頁面 1 mysql介紹 數據庫&#xff1a;存儲在硬盤上的文件系統…

VR虛擬展廳如何將客戶引流到線下?

VR虛擬展廳是一項很不錯的創新技術&#xff0c;將傳統的展覽內容以數字化形式呈現&#xff0c;為參觀者帶來全新的展示體驗&#xff0c;也為企業帶來了全新的宣傳機遇。 線上虛擬展廳目前有著兩種形式&#xff0c;一種是通過三維建模技術、虛擬現實技術等搭建的虛擬展廳&#x…

leetcode 474. 一和零

2023.8.15 class Solution { public:int findMaxForm(vector<string>& strs, int m, int n) {vector<vector<int>> dp(m1, vector<int>(n1,0));//遍歷物品for(string str : strs){int num_0 0;int num_1 0;for(char c : str){if(c 0) num_0;el…

Docker 容器內無法使用vim命令 解決方法

目錄 1. 問題所示2. 原理分析3. 解決方法1. 問題所示 進入Docker容器后 無法使用vim編輯器,出現如下問題:bash: vim: command not found 如圖所示: 想著通過apt-get 安裝vim,出現如下問題: root@b9f0fd330d5b:/# apt-get install vim Reading package lists... Done B…

ZooKeeper介紹

ZooKeeper是一個開放源代碼的分布式協調服務。ZooKeeper的設計目標是將那些復雜且容易出錯的分布式一致性服務封裝起來&#xff0c;構成一個高效可靠的原語集&#xff0c;并以一系列簡單易用的接口提供給用戶使用。 ZooKeeper是一個典型的分布式數據一致性的解決方案&#xff0…

如何通過 Keras 中的活動正則化減少泛化誤差

活動正則化提供了一種鼓勵神經網絡學習原始觀察的稀疏特征或內部表示的方法。 在自動編碼器(稱為稀疏自動編碼器)和編碼器-解碼器模型中尋求稀疏學習表示是很常見的,盡管該方法通常也可用于減少過度擬合并提高模型泛化到新觀察值的能力。 在本教程中,您將發現 Keras API …

spring入門基本介紹及注入方式---詳細介紹

一&#xff0c;spring的簡介 Spring是一個開源框架&#xff0c;它由Rod Johnson創建。它是為了解決企業應用開發的復雜性而創建的。 提供了許多功能強大且易于使用的特性&#xff0c;使得開發者能夠更加輕松地構建可維護且可擴展的應用程序&#xff0c;簡單來說: Spring使用基…

kaggle注冊不顯示驗證碼

edge瀏覽器 1.點擊瀏覽器右上角三個點 2.點擊擴展 3.點擊管理擴展 4.點擊獲取Microsoft Edge擴展&#xff0c;在左上角輸入Head Editor 5.輸入https://www.azurezeng.com/static/HE-GoogleRedirect.json 6.下載后&#xff0c;點保存 成功&#xff01;