微服務保護和熔斷降級技術Sentinel
1.微服務呼叫存在問題
由於一個服務不可用,有可能會導致一連串的微服務跟著不可用[伺服器支援的執行緒和併發數有限,請求一直阻塞,會導 致伺服器資源耗盡,從而導致所有其它服務都不可用], 形成級聯失敗,最終會導致服務雪崩問題。針對服務雪崩,有如 下幾種解決方案:
- 方案 1:超時處理:設定超時時間,請求超過一定時間沒有響應就返回錯誤資訊,不會無休止等待
- 方案 2: 倉壁模式, 倉壁模式來源於船艙的設計
- 方案 3: 斷路器模式:由斷路器統計業務執行的異常比例,如果超出閾值則會熔斷該業務,攔截訪問該業務的一切請求。 斷路器會統計訪問某個服務的請求數量,異常比, 當發現訪問服務 D 的請求異常比例過高時,認為服務 D 有導致雪崩的 風險,會攔截訪問服務 D 的一切請求,形成熔斷
- 方案 4: 限流,流量控制:限制業務訪問的 QPS,避免服務因流量的突增而故障
什麼是雪崩問題?
微服務之間相互呼叫,因為呼叫鏈中的⼀個服務故障,引起整個鏈路都無法訪問的情況。
限流是對服務的保護,避免因瞬間高併發流量而導致服務故障,進而避免雪崩。是⼀種預防措施。
超時處理、執行緒隔離、降級熔斷是在部分服務故障時,將故障控制在⼀定範圍,避免雪崩。是⼀種補救措施
2.前面整合了SpringCloud Hystrix實現了服務的降級,熔斷,限流.那Sentinel和Hystrix有什麼區別呢?
3.Sentinel 入門
①Sentinel安裝
我使用的是docker安裝方式,大家也可以自行用其他的方式.安裝好了以後直接在瀏覽器訪問:http://192.168.137.72:8858/
②Sentinel官網
https://sentinelguard.io/zh-cn/index.html
③流控、熔斷等都是針對簇點鏈路中的資源來設定的,因此我們可以點選對應資源後面的按鈕來設定規則
- 流控:流量控制
- 降級:降級熔斷
- 熱點:熱點引數限流,是限流的⼀種
- 授權:請求的許可權控制
④閾值型別
(1)測試QPS(Query Per Second):每秒請求數,就是說伺服器在一秒的時間內處理了多少個請求
快速重新整理頁面會出現下圖
(2)測試執行緒數流控:最大併發數是 3,超過 3 將直接流控,這裡我們藉助於 Jemeter 測試:。
Jemeter引數設定
測試結果
⑤流控模式
- 直接:統計當前資源的請求,觸發閾值時對當前資源直接限流,也是預設的模式
- 關聯:統計與當前資源相關的另一個資源,觸發閾值時,對當前資源限流
- 鏈路:統計從指定鏈路訪問到本資源的請求,觸發閾值時,對指定鏈路限流
(1)在sentinel-consumer-user9001服務controller中新增兩個介面用於測試
@Value("${server.port}")
private String port;
@GetMapping("/findById")
public User findById(Integer id) {
User user = userService.findById(id);
return user;
}
@GetMapping("/write")
public String write() {
return port;
}
設定關聯流控規則
Jemeter引數設定
測試結果
當兩個有競爭關係的資源 ⼀個優先順序較高,⼀個優先順序較低 ===> 可以使用關聯模式
注意:測試後面的規則,最好把前面的規則刪除掉,不然出現問題自己都蒙了......
⑥測試鏈路模式
(1)修改Service程式碼
@Override
@SentinelResource // Sentinel 預設只標記 Controller 中的方法為資源,如果要標記其它方法,需要利用@SentinelResource 註解
public void hello() {
System.out.println("你好");
}
(2)修改Controller程式碼
@GetMapping("/write")
public String write() {
userService.hello();
return port;
}
@GetMapping("/read")
public String read() {
userService.hello();
return port;
}
(3)修改yml配置檔案
sentinel:
web-context-unify: false #如果不關閉,所有controller層的方法對service層呼叫都認為是同一個根鏈路
(4)設定流控規則
測試結果:
流控模式小結
- 直接:對當前資源限流
- 關聯:高優先順序資源觸發閾值,對低優先順序資源限流
- 鏈路:閾值統計時,只統計從指定資源進入當前資源的請求,是對請求來源的限流
⑦流控效果
測試Warm up(預熱)流控模式:當系統執行時,有併發請求來訪問系統時,為了避免系統崩潰,可以設定一個閾值,讓專案可以處理請求的數量逐漸增加 到設定的閾值
測試結果:
測試 排隊等待:方式會嚴格控制請求通過的間隔 時間,也即是讓請求以均勻的速度通過,對應的是漏桶演算法.請求會進入佇列,按照閾值允許的時間間隔依次執行請求;如果請求預期等待時⻓大於超時時間,直接拒絕
編輯流控規則
修改程式碼
@GetMapping("/findById")
public Movie findById(@RequestParam("id") Integer id){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(port);
return movieService.findById(id);
}
測試結果:
⑧熱點 key 限流:是分別統計引數值相同的請求,判斷是 否超過 QPS 閾值。
新增請求介面
@SentinelResource(value = "hot")
@GetMapping("/resource/{hid}")
public String testHotResource(@PathVariable("hid") Long hid) {
System.out.println(hid);
return port;
}
修改熱點key規則,點選左側選單欄配置資訊更完善
引數為1時,每秒請求數最大為3
引數為2是,每秒請求數最大為5
雖然限流可以儘量避免因高併發而引起的服務故障,但服務還會因為其它原因而故障。而要將這些故障控制在一定範圍, 避免雪崩,就要靠執行緒隔離(艙壁模式)和熔斷降級手段了。 不管是執行緒隔離還是熔斷降級,都是對客戶端(呼叫方)的保護。
⑨執行緒隔離
執行緒隔離有兩種方式實現:
- 1.執行緒池隔離 (Hystrix 兩種隔離方式都支援)
- 2.訊號量隔離(Sentinel 只支援訊號量隔離)
執行緒池隔離和訊號量隔離的區別:
執行緒池隔離與訊號量隔離各自的應用場景:
Hystrix 支援訊號量隔離與執行緒池隔離,預設使用的是執行緒池隔離,配置方式如下
hystrix:
command:
default:
execution:
isolation:
strategy: Thread # 預設是Thread, 可選Thread(執行緒池隔離)|Semaphore(訊號量隔離)
Sentinel 只支援訊號量隔離,配置方式如下
這裡的執行緒數是:該資源能使用用的 tomcat 執行緒數的最大值。也就是通過限制執行緒數量,實現艙壁模式。
執行緒隔離小結:
- 執行緒隔離的兩種手段是?訊號量隔離、執行緒池隔離
- 訊號量隔離的特點是?基於計數器模式,簡單,開銷小
- 執行緒池隔離的特點是?基於執行緒池模式,有額外開銷,但隔離控制更強
⑩熔斷降級
sentinel 與 feign 整合之方式⼀:FallbackClass,無法對遠端呼叫的異常做處理
(1)修改ymlp配置檔案
feign:
sentinel:
enabled: true # 開啟feign對sentinel的支援
(2)編寫一個降級類,實現遠端呼叫的介面
package com.qbb.cloud2022.feign;
import com.qbb.cloud2022.com.qbb.springcloud.entity.Movie;
import org.springframework.stereotype.Component;
/**
* @author QiuQiu&LL (個人部落格:https://www.cnblogs.com/qbbit)
* @version 1.0
* @date 2022-04-07 23:34
* @Description:
*/
@Component
public class FeignMovieServiceFallBack implements FeignMovieService {
@Override
public Movie findById(Integer id) {
Movie movie = new Movie(-1, "網路異常,請稍後再試~~~~");
return movie;
}
}
(3)在遠端呼叫的介面上新增屬性
@FeignClient(value = "sentinel-provider-user9101",fallback = FeignMovieServiceFallBack.class)
測試一下:
sentinel 與 feign 整合之方式二:FallbackFactory,可以對遠端呼叫的異常做處理,我們選擇這種
(1)修改ymlp配置檔案
feign:
sentinel:
enabled: true # 開啟feign對sentinel的支援
(2)建立一個Factory類實現FallBackFactory介面
package com.qbb.cloud2022.feign;
import com.qbb.cloud2022.com.qbb.springcloud.entity.Movie;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
/**
* @author QiuQiu&LL (個人部落格:https://www.cnblogs.com/qbbit)
* @version 1.0
* @date 2022-04-07 23:34
* @Description:
*/
@Component
public class FeignMovieServiceFallBackFactory implements FallbackFactory {
@Override
public Object create(Throwable throwable) {
throwable.printStackTrace();
return new Movie(-1, "網路異常,請稍後再試~~~~");
}
}
(3)在遠端呼叫的介面上新增屬性
@FeignClient(value = "sentinel-provider-user9101",fallbackFactory = FeignMovieServiceFallBackFactory.class)
測試一下:
控制檯直接報錯
熔斷器的三種狀態
熔斷降級是解決雪崩問題的重要手段。其思路是由斷路器統計服務呼叫的異常比例、慢請求比例,如果超出閾值則會熔 斷該服務。即攔截訪問該服務的一切請求;而當服務恢復時,斷路器會放行訪問該服務的請求
斷路器熔斷策略有三種:慢呼叫、異常比例、異常數
上圖的意思是:RT 超過 500ms 的呼叫是慢呼叫,如果請求量超過 10 次,並且慢呼叫比例不低於 0.5,則觸發熔斷,熔斷時長為 5 秒。然後進入 half-open 狀態,放行一次請求做測試
修改被呼叫方的程式碼
@GetMapping("/findById")
public Movie findById(@RequestParam("id") Integer id) {
if (id == 2) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(port);
return movieService.findById(id);
}
測試一下:
Sentinel 熔斷降級的策略有哪些?
- 慢呼叫比例:超過指定時⻓的呼叫為慢呼叫,統計單位時⻓內慢呼叫的比例,超過閾值則熔斷
- 異常比例:統計單位時⻓內異常呼叫的比例,超過閾值則熔斷
- 異常數:統計單位時⻓內異常呼叫的次數,超過閾值則熔斷