學習 spring-cloud-aibaba第五篇,服務容錯 Sentinel 上篇


特別聲明:整理自慕課網大目師兄的微服務視頻,鏈接:https://coding.imooc.com/learn/list/358.html
前情提要:nacos上註冊了content-centeruser-center兩個服務,content-center使用Feign調用user-center服務,使用Ribbon做負載均衡,sentinel實現服務容錯!sentinel使用簡單,精通就難了,可以配置的選擇很多,可以操作的餘地也很足!

1.爲什麼需要服務容錯?

1.1 雪崩效應

在這裏插入圖片描述
雪崩效應(級聯故障):如圖所示,C,D服務調用B服務,B服務調用A服務,如果A服務突然發生故障,那麼B服務調用A服務就得不到返回,直到請求超時,在超時之前的那段時間內,請求一直在等待,簡直欲穿秋水,一個請求就是一個線程,線程一直處於阻塞狀態,會一直佔用服務器的資源,比如內存,cpu;如果B的併發很高,這樣阻塞的線程很多,那麼B服務器再也沒有資源去創建新的線程,於是B也掛了,然後C,D服務又請求不到B服務了…然後C,D服務也掛了。因爲A服務的故障,BCD沒有做任何處理,都掛了,這就是雪崩效應

1.2 什麼是服務容錯

我的理解就是服務容錯的目的就是保護自己服務的正常運行。比如B服務碰到上面那種請求等待導致線程太多的時候,我就限流,某某請求的線程不得超過10個,超過10個就不再接受新的請求,直接返回被限流錯誤提示,這樣B服務就不會因爲太多線程耗盡內存而亡了

1.3 常見的容錯方案

  • 超時
    最容易想到的方案,把請求時間設置的很短,這樣線程釋放的足夠快,B服務就不會那麼容易被耗死了
    體現思想:天下武功,唯快不破!
  • 限流
    我們經過測試,發現某個請求能承受的最大QPS(每秒查詢率)是1000,那我們就把這個請求的QPS閾值設置成800,超過了這個閾值,請求直接返回被限流的錯誤(限流功能僅僅是Setinel衆多功能當中的一個)
    體現思想:世相萬變,我心不變,他弱由他弱,清風拂山崗,他強由他強,明月照大江!
  • 倉壁模式
    創造很多的隔斷間,每個隔斷間都有一個自己的線程池,你自己的線程池滿了,後續請求按照線程池的規則排隊,還是啥的就行了,不會影響到其它的隔斷間。可以把Controller當作隔斷間,也可以是其它的,反正就是這個意思
    體現思想:不把雞蛋放一個籃子裏!
  • 斷路器模式
    檢測一定時間內的錯誤率,錯誤數,比如5秒之內錯誤率,錯誤次數,達到某個閾值,就認爲B服務所調用的A服務掛了,我就跳閘,就不會堆積那麼多線程等待了,然後在10秒之後(稱作斷路器時間窗口),斷路器變成半開狀態,此狀態向A再發送僅僅一次請求,如果這次請求又失敗了,我再跳閘,默默的等10秒(斷路器時間窗口,不是非得10秒,我只是舉例子,值自己可以設定),斷路器又變成半開狀態,再次向A發送一次請求,如果這次請求成功了,斷路器就徹底恢復,閘徹底閉合(斷路器模式也是Setinel衆多功能當中的一個)
    體現思想:可以自我修復的高級保險絲!

2.部署Sentinel控制檯

Sentinelnacos有點像,都有個控制檯

2.1 下載Sentinel.jar包

2.2 運行Sentinel.jar包

Sentinel的端口是8080,所以你得把8080端口先空出來

一般執行下面這個命令就行了,不過窗口關閉,服務也會停掉

 java -jar sentinel-dashboard-1.6.3.jar

這個命令是linux系統後臺窗口運行的,窗口關閉,服務也不會停止

nohup java -jar sentinel-dashboard-1.6.3.jar &

2.3 登錄Sentinel控制檯

ip+端口號訪問服務,用戶名和密碼都是:sentinel,我用本地的sentinel
在這裏插入圖片描述
在這裏插入圖片描述

3.微服務整合Sentinel

依舊三板斧

3.1 加依賴

sentinel建立在springbootactuator組件上

		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

3.2 寫註解

暫無註解

3.3 寫配置

指定sentinel 控制檯地址

spring:
  cloud:
    sentinel:
      transport:
        # 指定 sentinel 控制檯地址
        dashboard: localhost:8080
management:
  endpoints:
    web:
      exposure:
        # 暴露出所有actuator監控的端點
        include: '*'

3.4 懶加載

sentinel是懶加載的,所以得訪問一下content-center服務的http://localhost:8081/poem/testRibbon接口,再刷新Sentinel控制檯,就能看到content-center
在這裏插入圖片描述

4.簇點鏈路

  • 給資源添加規則的入口
  • 被請求的路徑,都稱作資源,會在簇點鏈路裏顯示出來,沒有被請求的就不會顯示出來
    在這裏插入圖片描述

5.流控規則限流

5.1 參數解釋

在這裏插入圖片描述

參數名 含義
資源名 即限流規則的作用對象
針對來源 流控針對的調用來源(服務級別),若爲 default 則不區分調用來源
閾值類型 QPS(每秒查詢率) 或併發線程數(感覺這個就是倉壁模式)
單機閾值 限流閾值,超過這個值就執行流控規則
流控模式 直接,關聯,鏈路
流控效果 直接拒絕、Warm Up、勻速排隊
是否集羣 這個功能好像還不能用

比較難以理解的就是流控模式流控效果

5.1.1 流控模式

基於調用關係的流量控制

  • 直接
    直接針對資源本身
  • 關聯
    當兩個資源之間具有資源爭搶或者依賴關係的時候,這兩個資源便具有了關聯。當關聯的資源達到閾值,就限流自己,讓自己讓出系統資源給關聯的資源,也就是說在限流自己保護關聯資源
  • 鏈路
    資源通過調用關係,相互之間構成一棵調用樹,老抽象了,下面的common和chain/b就是樹的關係,這就是一條鏈路
    在這裏插入圖片描述

5.1.2 流控效果

  • 直接拒絕
    QPS線程數超過規則的閾值後,新的請求就會被立即拒絕,拒絕方式爲拋出FlowException。這種方式適用於對系統處理能力確切已知的情況下,比如通過壓測確定了系統的準確水位時
  • Warm Up
    當流量突然增加時,直接把系統拉昇到高水位可能瞬間把系統壓垮。通過"冷啓動",讓通過的流量緩慢增加,在一定時間內逐漸增加到閾值上限,給冷系統一個預熱的時間,避免冷系統被壓垮
  • 勻速排隊
    嚴格控制請求通過的間隔時間,也即是讓請求以均勻的速度通過,對應的是漏桶算法。這種方式主要用於處理間隔性突發的流量,例如消息隊列。想象一下這樣的場景,在某一秒有大量的請求到來,而接下來的幾秒則處於空閒狀態,我們希望系統能夠在接下來的空閒期間逐漸處理這些請求,而不是在第一秒直接拒絕多餘的請求

5.2 測試三種流控模式

5.2.1 直接

默認就是直接

  • 添加規則
    對資源testSentinel/QPSFlowControl添加如下流控規則:如果QPS(每秒查詢率)閾值超過1,就直接返回失敗
    在這裏插入圖片描述
    在這裏插入圖片描述
  • 測試
    快速多次刷新,可以看到,通過6次請求,拒絕14次,規則起作用了
    在這裏插入圖片描述
    在這裏插入圖片描述

5.2.2 關聯

  • 寫了兩個請求
@RestController
@Slf4j
@RequestMapping("/testSentinel")
public class FlowControl {

    @GetMapping("related/a")
    public String flowRelatedA(){
        log.info("我是被限流的資源......");
        return "related/a";
    }

    @GetMapping("related/b")
    public String flowRelatedB(){
        log.info("我是被關聯資源,不是限流我......");
        return "related/b";
    }
  • 配置/testSentinel/related/a的限流
    如果/testSentinel/related/b的QPS達到1,那麼限流/testSentinel/related/a
    -
  • 使用Postman 25秒內訪問/testSentinel/related/b 50次,每500ms一次,QPS=2 > 閾值1,滿足限流條件
    postman請求之前,可以正常訪問/testSentinel/related/a
    在這裏插入圖片描述
    啓動postman請求之後:
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述
    從控制檯可以看到/testSentinel/related/b 50次請求全通過,但是/testSentinel/related/a的請求就被拒絕了,測試通過

5.2.3 鏈路

  • 測試代碼,兩個請求資源:/testSentinel/chain/a,/testSentinel/chain/b
    flowService.common() 註解爲sentinel資源,ab都使用了common方法
@RequestMapping("/testSentinel")
public class FlowController {

    @Autowired
    FlowService flowService;
    
    @GetMapping("chain/a")
    public String chainA(){
        flowService.common();
        return "chain/a";
    }

    @GetMapping("chain/b")
    public String chainB(){
        flowService.common();
        return "chain/b";
    }
@Service
@Slf4j
public class FlowService {

    @SentinelResource
    public void common(){
        log.info("common......");
    }
}

5.3 測試三種流控效果

5.3.1 快速失敗

上一節測試的默認都是這種流控效果,返回限流消息或者500錯誤

5.3.2 Warm Up

初始閾值設定閾值/codeFactor(默認3),經過預熱時長閾值升高到設定閾值,讓可通過的流量緩慢增長

  • 修改單擊閾值爲6,流控效果選擇 Warm Up
    實際上初始閾值=6/3,爲2,經過10秒之後,閾值升高到6
    在這裏插入圖片描述
  • 測試
    使用postman測試,0.1秒請求一次,總共請求200次,QPS爲10 ,持續20http://localhost:8081/testSentinel/QPSFlowControl

在這裏插入圖片描述
sentinel的實時監控臺
21:06:46秒時,通過QPS2,符合 6/3=2
在這裏插入圖片描述
21:06:58秒開始,通過QPS6,後面穩定6,直到QPS自己降下來,預熱時間
58-46=12秒,略大於設置的10秒。總體基本符合限流設置!
在這裏插入圖片描述

5.3.3 排隊等待

這個限流效果只對閾值類型QPS的起作用

  • 設置/testSentinel/QPSFlowContro限流規則
    設置之前清除它其它的容錯規則,以免被幹擾。設置閾值2,超時時間10秒,
    規則效果:QPS超過閾值的請求,不放棄請求,而是讓請求排隊等待被執行,服務以一秒2次的速度處理排隊的請求,如果某個請求的等待時間超過10秒,纔會返回失敗
    在這裏插入圖片描述
  • 測試
    使用postman以一秒10次的速度請求http://localhost:8081/testSentinel/QPSFlowControl 100次,可以看到QPS一直是2100請求全部通過,沒有請求被丟棄,符合規則預期!
    在這裏插入圖片描述
    在這裏插入圖片描述

6.降級規則限流

在這裏插入圖片描述

6.1 三種降級策略

6.1.1 RT (Response Time)

6.1.1.1 釋義

當1s內持續進入5個請求,對應時刻的平均響應時間(秒級統計,單位毫秒)均超過閾值ms,斷路器打開,返回請求失敗,知道時間窗口設置的時間結束,關閉降級
在這裏插入圖片描述

  • RT默認上限是4900 ms
    如需改動,可以通過下面的配置項來設置
-Dcsp.sentinel.statistic.max.rt=xxx

6.1.1.2 測試

  • 測試準備代碼
@RestController
@Slf4j
@RequestMapping("/down")
public class DownController {

    @GetMapping("rt/a")
    public String rtA(){
        log.info("rtA....");
        return "rt/a";
    }

}
  • 新增降級規則
    1s內持續進入5個請求,平均響應時間 > 1ms,就返回錯誤提示,直到4秒之後恢復正常
    在這裏插入圖片描述
  • 瘋狂刷新 http://localhost:8081/down/rt/a,考驗手速的時候到了,RT肯定會大於1ms的,於是降級了在這裏插入圖片描述
    4秒,再次訪問,正常了
    在這裏插入圖片描述

6.1.2 異常比率

6.1.2.1 釋義

當資源的每秒請求量 >= 5,並且每秒異常總數佔通過量的比值超過閾值,資源進入降級狀態;接下的時間窗口之後,降級恢復
異常比率的閾值範圍是 [0.0, 1.0],代表 0% - 100%
在這裏插入圖片描述

6.1.2.2 測試

  • 寫個必拋異常的方法
    要想異常被統計,必須 Tracer.trace(t)
    @GetMapping("rt/b")
    public String rtB() {
        try {
            log.info("rtB....");
            throw new RuntimeException("throw runtime ");
        } catch (Throwable t) {
            Tracer.trace(t);
        }
        return "rt/b";
    }
  • 配置規則
    資源的每秒請求量 >= 5,秒級異常比例 > 0.1,降級,4秒之後恢復
    在這裏插入圖片描述
  • 測試
    瘋狂刷新 http://localhost:8081/down/rt/b,必報異常,所有異常比率 > 0.1
    在這裏插入圖片描述
    4秒之後在刷新:
    在這裏插入圖片描述

6.1.3 異常數

6.1.3.1 釋義

資源近1分鐘的異常數目超過閾值之後會進行降級,統計時間窗口是分鐘級別的,所以時間窗口最好大於60s
在這裏插入圖片描述

6.1.3.2 測試

比較好理解,不測試了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章