微服務保護 Sentinel

1.初識Sentinel

文章目錄

  • 1.初識Sentinel
    • 1.1.雪崩問題及解決方案
      • 1.1.1.雪崩問題
      • 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模式

1.1.雪崩問題及解決方案

1.1.1.雪崩問題

微服務中,服務間調用關系錯綜復雜,一個微服務往往依賴于多個其它微服務。

在這里插入圖片描述

如圖,如果服務提供者I發生了故障,當前的應用的部分業務因為依賴于服務I,因此也會被阻塞。此時,其它不依賴于服務I的業務似乎不受影響。

在這里插入圖片描述

但是,依賴服務I的業務請求被阻塞,用戶不會得到響應,則tomcat的這個線程不會釋放,于是越來越多的用戶請求到來,越來越多的線程會阻塞:

在這里插入圖片描述

服務器支持的線程和并發數有限,請求一直阻塞,會導致服務器資源耗盡,從而導致所有其它服務都不可用,那么當前服務也就不可用了。

那么,依賴于當前服務的其它服務隨著時間的推移,最終也都會變的不可用,形成級聯失敗,雪崩就發生了:

在這里插入圖片描述

1.1.2.超時處理

解決雪崩問題的常見方式有四種:

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

在這里插入圖片描述

1.1.3.倉壁模式

方案2:倉壁模式

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

在這里插入圖片描述

船艙都會被隔板分離為多個獨立空間,當船體破損時,只會導致部分空間進入,將故障控制在一定范圍內,避免整個船體都被淹沒。

于此類似,我們可以限定每個業務能使用的線程數,避免耗盡整個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介紹和安裝

1.3.1.初識Sentinel

Sentinel是阿里巴巴開源的一款微服務流量控制組件。官網地址:https://sentinelguard.io/zh-cn/index.html

Sentinel 具有以下特征:

?豐富的應用場景:Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的范圍)、消息削峰填谷、集群流量控制、實時熔斷下游不可用應用等。

?完備的實時監控:Sentinel 同時提供實時的監控功能。您可以在控制臺中看到接入應用的單臺機器秒級數據,甚至 500 臺以下規模的集群的匯總運行情況。

?廣泛的開源生態:Sentinel 提供開箱即用的與其它開源框架/庫的整合模塊,例如與 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相應的依賴并進行簡單的配置即可快速地接入 Sentinel。

?完善的 SPI 擴展點:Sentinel 提供簡單易用、完善的 SPI 擴展接口。您可以通過實現擴展接口來快速地定制邏輯。例如定制規則管理、適配動態數據源等。

1.3.2.安裝Sentinel

1)下載

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

課前資料也提供了下載好的jar包:

在這里插入圖片描述

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測試

如果沒有用過jmeter,可以參考課之前提供的文章《Jmeter快速入門》

打開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為15

2.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.隔離和降級

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

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

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

在這里插入圖片描述

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

在這里插入圖片描述
-20210715173428073.png&pos_id=img-ghtnUYTn-1700744619284)

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

而我們的微服務遠程調用都是基于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:

在這里插入圖片描述
Fimage-20210716122403502.png&pos_id=img-ejkvPBg5-1700744619285)

代碼:

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的線程隔離

用法說明

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

在這里插入圖片描述
image-20210716123411217.png&pos_id=img-mEJMTLLP-1700744619286)

  • 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模式

詳細步驟可以參考前文章資料的《sentinel規則持久化》:

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

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

相關文章

C語言—指針初始化

指針初始化&#xff1a;指針初始情況下指向哪個地址。兩種指針初始化方式 1、聲明指針時就進行指針初始化&#xff0c;告訴指針指向哪個地址 #include <stdio.h> int main () {int i5;int *p&i;return 0; }2、聲明指針時未進行初始化&#xff0c;在后期把指向的地…

MacM1(ARM)安裝Protocol Buffers

MacM1(ARM)安裝Protocol Buffers 本文目錄 MacM1(ARM)安裝Protocol Buffers3.21之前版本安裝使用configure3.22之后版本安裝使用cmake使用編譯后的版本 protobuf下載地址&#xff1a;https://github.com/protocolbuffers/protobuf/releases 在運行./autogen.sh或./configure命…

大表查詢如何優化?

大表查詢的優化方法有以下幾種&#xff1a; 索引優化&#xff1a;通過建立合理高效的索引&#xff0c;提高查詢的速度。SQL優化&#xff1a;組織優化SQL語句&#xff0c;使查詢效率達到最優&#xff0c;在很多情況下要考慮索引的作用。水平拆表&#xff1a;如果表中的數據呈現…

curl添加https服務

CURL支持的通信協議有FTP、FTPS、HTTP、HTTPS、TFTP、SFTP、Gopher、SCP、Telnet、DICT、FILE、LDAP、LDAPS、IMAP、POP3、SMTP和RTSP。 首選刪除系統自帶的openssl&#xff0c;因為他只有可執行程序和庫&#xff0c;沒有頭文件。 sudo apt-get remove openssl openssl官網&am…

CentOS7磁盤掛載

1 引言 本文主要講述CentOS7磁盤掛載相關知識點和操作。 2 磁盤掛載 步驟1&#xff1a; 查看機器所掛硬盤及分區情況 fdisk -l查詢結果&#xff1a; 由上圖可以看到該結果包含&#xff1a;硬盤名稱、硬盤大小等信息。 屬性解釋說明Disk /dev/vda硬盤名稱53.7G磁盤大…

6S精益管理必備裝備降低物料損耗

在工廠生產環境中&#xff0c;設備管理是確保生產效率和質量的關鍵因素之一。6S管理方法是一種源自日本的管理體系&#xff0c;旨在通過整頓、整理、清掃、清潔、素養、遵守六個步驟&#xff0c;實現工作環境的優化和管理的高效。 倉庫管理中&#xff0c;庫存損耗一直是企業面…

分布式篇---第四篇

系列文章目錄 文章目錄 系列文章目錄前言一、分布式ID生成有幾種方案?二、冪等解決方法有哪些?三、常見負載均衡算法有哪些?前言 前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到網站,這篇文章男女通用,看懂了就去分享給…

多回路交流三相單相電壓電流電量監測開口式互感器適用多種環境用電能耗監控

1 產品概述 多回路交流無線電壓電流傳感器/電量采集監測儀搭配多路開口式互感器&#xff0c;可以監控采集三相電壓、電流、功率和電量等信息&#xff0c;可用于能耗采集監控。支持RS485和4G網絡接口&#xff0c;數據可以對接客戶指定的第三方云平臺。本產品可實現單相/三相用電…

Spring事務的實現方式和實現原理;事務聲明的方式,Spring的事務傳播行為,spring事務的實現原理

Spring事務的實現方式和實現原理 Spring事務的本質其實就是數據庫對事務的支持&#xff0c;沒有數據庫的事務支持&#xff0c;spring是無法提供事務功能的。真正的數據庫層的事務提交和回滾是通過binlog或者redo log實現的。 什么是事務 數據庫事務是指作為單個邏輯工作單元執…

發布本地(sap hana)Jar包到Maven私有倉庫

在控制臺執行如下命令&#xff1a; mvn deploy:deploy-file -DgroupId"com.sap.cloud.db.jdbc" -DartifactId"ngdbc" -Dversion"2.0.13" -Dpackaging"jar" -Dfile"F:\sap_ngdbc\ngdbc-2.0.13.jar" -DrepositoryId"rel…

Co-DETR:DETRs與協同混分配訓練論文學習筆記

論文地址&#xff1a;https://arxiv.org/pdf/2211.12860.pdf 代碼地址&#xff1a; GitHub - Sense-X/Co-DETR: [ICCV 2023] DETRs with Collaborative Hybrid Assignments Training 摘要 作者提出了一種新的協同混合任務訓練方案&#xff0c;即Co-DETR&#xff0c;以從多種標…

網站會遭受那些攻擊,要怎么應對

隨著互聯網的普及和發展&#xff0c;很多企業或個人都建立了自己的網站&#xff0c;這些網站不僅可以展示企業或個人的信息&#xff0c;還可以提供各種服務和交流平臺。但是&#xff0c;在運營網站的過程中&#xff0c;很多人都會遇到網站被流量攻擊的情況&#xff0c;這種情況…

gmapping仿真

文章目錄 獲取源碼安裝依賴項編譯簡單場景運行gmapping開啟鍵盤控制通過launch文件來啟動gmappingGmapping建圖的參數設置地圖的保存和加載參考 獲取源碼 cd ~/catkin_ws/src/ git clone https://gitcode.com/weixin_42990464/wpr_simulation.git git clone https://gitcode.c…

【開源】基于Vue.js的農村物流配送系統的設計和實現

項目編號&#xff1a; S 024 &#xff0c;文末獲取源碼。 \color{red}{項目編號&#xff1a;S024&#xff0c;文末獲取源碼。} 項目編號&#xff1a;S024&#xff0c;文末獲取源碼。 目錄 一、摘要1.1 項目介紹1.2 項目錄屏 二、功能模塊2.1 系統登錄、注冊界面2.2 系統功能2.2…

java使用poi框架導出excel文件名命名為中文的方法

最近使用poi框架實現自動化報表導入導出功能&#xff0c;但是遇到一個問題&#xff0c;導出的表格命名為中文時不被識別&#xff0c;直接會以接口名為文件名導出&#xff0c;那么如何解決這個問題呢&#xff1f; 三行代碼解決&#xff1a; String fileName "xxxx統計表-…

小程序:用戶查找英語單詞的意思 ← Python字典

【程序分析】 ● 字典中的條目是沒有順序的。 ● 可以對字典使用如下方法&#xff1a; keys()、values()、 items()、 clear()、 get(key)、 pop(key) 和popitem()【程序代碼】 dictionary{"dog":"狗","apple":"蘋果","banana&q…

Java字節碼指令集概述及分類詳解

Java全能學習面試指南&#xff1a;https://javaxiaobear.cn 1、字節碼指令集與解析概述 Java字節碼對于虛擬機&#xff0c;就好像匯編語言對于計算機&#xff0c;屬于基本執行指令。 Java 虛擬機的指令由一個字節長度的、代表著某種特定操作含義的數字&#xff08;稱為操作碼&a…

醫院供暖換熱站遠程監控案例

醫院供暖換熱站遠程監控案例 本文針對醫院換熱站遠程監控系統存在的問題&#xff0c;提出了一種基于物聯網技術的解決方案。通過使用云平臺功能&#xff0c;實現對換熱站設備的遠程監控和管理&#xff0c;提高系統運行效率&#xff0c;降低運維成本。 一&#xff0e;痛點 1、…

C語言——深入理解指針(1)

目錄 1.內存與地址 1.1 什么是內存 1.2 編址 2. 指針的變量和地址 2.1 取地址&#xff08;&&#xff09; 2.2 指針變量 2.3 解引用 2.4 指針變量大小 3. 指針變量類型存在的意義 3.1 不同類型指針的解引用 3.2 指針對整數的運算&#xff08;&#xff0c;-&#…

(10)ATF MMU轉換表

MMU簡介 MMU&#xff08;內存管理單元&#xff09;負責將軟件使用的虛擬地址轉換為內存系統中使用的物理地址。MMU包括兩個模塊&#xff1a;TLB&#xff08;Translation Lookaside Buffer&#xff09;和TWU&#xff08;Table Walk Unit&#xff09;。TLB緩存最近使用的轉換&am…