Sentinel

一窑眯、前言:和Hystrix作對(duì)比

Hystrix:

  • 1、需要我們自己手工搭建監(jiān)控平臺(tái)
  • 2医窿、沒(méi)有一套web界面磅甩,不可以給我們進(jìn)行更加細(xì)粒度化的配置流控、速率控制姥卢、服務(wù)熔斷卷要、服務(wù)降級(jí)

Sentinel:

  • 1、單獨(dú)一個(gè)組件独榴,可以獨(dú)立出來(lái)
  • 2僧叉、直接界面化的細(xì)粒度統(tǒng)一配置

二、Sentinel(哨兵)是什么

官網(wǎng):https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D

隨著微服務(wù)的流行棺榔,服務(wù)和服務(wù)之間的穩(wěn)定性變得越來(lái)越重要瓶堕。Sentinel 以流量為切入點(diǎn),從流量控制症歇、熔斷降級(jí)郎笆、系統(tǒng)負(fù)載保護(hù)等多個(gè)維度保護(hù)服務(wù)的穩(wěn)定性。主要就是服務(wù)雪崩忘晤、服務(wù)降級(jí)题画、服務(wù)熔斷、服務(wù)限流

主要特性

三德频、Sentinel的下載安裝運(yùn)行

Sentinel分為兩部分:

核心庫(kù)(java客戶端):不依賴任何框架/庫(kù)苍息,能夠運(yùn)行于所有java運(yùn)行環(huán)境,同時(shí)對(duì)Dubbo/Spring Cloud等框架也有較好的支持壹置。
控制臺(tái)(Dashboard):基于Spring Boot開(kāi)發(fā)竞思,打包后可以直接運(yùn)行,不需要額外的Tomcat等應(yīng)用容器钞护。

下載Sentinel的jar包盖喷,然后直接java -jar 運(yùn)行即可 ,Sentinel的用戶和密碼默認(rèn)都是Sentinel

四难咕、Sentinel的初始化監(jiān)控

1课梳、建立一個(gè)module被Sentinel保護(hù)
2、pom

//sentinel的依賴
<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
//后面做持久化會(huì)用到
<dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
//添加openfeign的依賴余佃,后面會(huì)用到
<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

3暮刃、yml

server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        #Nacos服務(wù)注冊(cè)中心地址
        server-addr: localhost:8848

    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: localhost:8080
        #默認(rèn)8719端口,假如被占用會(huì)自動(dòng)從8719+1依次掃描
        port: 8719

management:
  endpoints:
    web:
      exposure:
        include: '*'

4爆土、主啟動(dòng)類

@SpringBootApplication
@EnableDiscoveryClient
public class MainApp8401 {
    public static void main(String[] args) {
        SpringApplication.run(MainApp8401.class,args);
    }
}

5椭懊、業(yè)務(wù)類

@RestController
public class FlowLimitController {


    @GetMapping("/testA")
    public String testA() {
        return "testA";
    }

    @GetMapping("/testB")
    public String testB() {
        return "testB";
    }
}

6、測(cè)試

此時(shí)訪問(wèn)一下controller中指定的路徑步势,Sentinel就將對(duì)應(yīng)用進(jìn)行保護(hù)了氧猬,因?yàn)镾entinel采取的是懶加載背犯,訪問(wèn)localhost:8080也就可以看到應(yīng)用。

界面展示

五盅抚、Sentinel的流量控制

流量控制(flow control)漠魏,其原理是監(jiān)控應(yīng)用流量的 QPS 或并發(fā)線程數(shù)等指標(biāo),當(dāng)達(dá)到指定的閾值時(shí)對(duì)流量進(jìn)行控制妄均,以避免被瞬時(shí)的流量高峰沖垮柱锹,從而保障應(yīng)用的高可用性。
資源名:唯一名稱丛晦,默認(rèn)請(qǐng)求路徑

閾值類型/單機(jī)閾值:
①Q(mào)PS(每秒鐘的請(qǐng)求數(shù)量):當(dāng)調(diào)用該api的QPS達(dá)到閾值的時(shí)候,進(jìn)行限流
②線程數(shù):當(dāng)調(diào)用該api的線程數(shù)達(dá)到閾值的時(shí)候進(jìn)行限流

流控模式:
①直接:api達(dá)到限流條件時(shí)提陶,直接限流
②關(guān)聯(lián):當(dāng)關(guān)聯(lián)的資源達(dá)到閾值時(shí)烫沙,就限流自己。
③鏈路:只記錄指定鏈路上的流量隙笆,如果達(dá)到閾值锌蓄,就進(jìn)行限流

流控效果
①快速失敗:直接失敗撑柔,拋異常
②Warm up:根據(jù)codeFactor(冷加載因子瘸爽,默認(rèn)3)的值,從閾值/codeFactor铅忿,經(jīng)過(guò)預(yù)熱時(shí)長(zhǎng)剪决,才達(dá)到設(shè)置的QPS閾值
③排隊(duì)等待:勻速排隊(duì),讓請(qǐng)求以勻速的速度通過(guò)檀训,閾值類型必須為QPS柑潦,否則無(wú)效

1、QPS直接快速失敗報(bào)錯(cuò)

表示一秒鐘內(nèi)點(diǎn)擊一次峻凫,如果超過(guò)就會(huì)直接頁(yè)面報(bào)錯(cuò)

出錯(cuò)頁(yè)面

2渗鬼、QPS和線程作對(duì)比
如下圖所示,在這里都以設(shè)置為1作比較荧琼,QPS表示的是每秒的請(qǐng)求數(shù)量譬胎,如果一旦一秒鐘超過(guò)了1個(gè),就相當(dāng)于是有一扇門(mén)直接給擋住了命锄,然后直接報(bào)錯(cuò)堰乔。線程就像是坝撑,進(jìn)去了這扇門(mén)斟赚,不管有多少數(shù)據(jù)都可以進(jìn)來(lái),但是只能一個(gè)個(gè)的依次的來(lái)處理陵霉,就像是銀行的業(yè)務(wù)人員被盈,一旦兩個(gè)想同時(shí)訪問(wèn)析孽,不好意思搭伤,不行。
QPS和線程數(shù)對(duì)比

3袜瞬、QPS關(guān)聯(lián)模式快速報(bào)錯(cuò)(因?yàn)槲⒎?wù)中兩個(gè)服務(wù)之間是有關(guān)聯(lián)的怜俐,比如說(shuō)支付接口掛了,那你下單接口也歇一歇)當(dāng)與A關(guān)聯(lián)的B達(dá)到閾值時(shí)邓尤,A就限流自己拍鲤,B惹事A遭殃

@GetMapping("/testA")
    public String testA() {
        return "testA";
    }

    @GetMapping("/testB")
    public String testB() {
        return "testB";
    }
關(guān)聯(lián)配置
用postman進(jìn)行訪問(wèn)測(cè)試

結(jié)果訪問(wèn)testA報(bào)錯(cuò)

4、QPS warm up流控效果
Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式汞扎,即預(yù)熱/冷啟動(dòng)方式季稳。當(dāng)系統(tǒng)長(zhǎng)期處于低水位的情況下,當(dāng)流量突然增加時(shí)澈魄,直接把系統(tǒng)拉升到高水位可能瞬間把系統(tǒng)壓垮景鼠。通過(guò)"冷啟動(dòng)",讓通過(guò)的流量緩慢增加痹扇,在一定時(shí)間內(nèi)逐漸增加到閾值上限铛漓,給冷系統(tǒng)一個(gè)預(yù)熱的時(shí)間,避免冷系統(tǒng)被壓垮鲫构。詳細(xì)文檔可以參考 流量控制 - Warm Up 文檔浓恶,具體的例子可以參見(jiàn) WarmUpFlowDemo

通常冷啟動(dòng)的過(guò)程系統(tǒng)允許通過(guò)的 QPS 曲線如下圖所示:

image

如下圖所示结笨,我們最后想要設(shè)置的值是單機(jī)閾值是10包晰,但是不想讓他一下子到10,而是想讓他慢慢的增長(zhǎng)炕吸,一開(kāi)始的單機(jī)閾值設(shè)置為10(單機(jī)閾值)/3(冷加載因子)=3.3杜窄,5秒(預(yù)熱時(shí)長(zhǎng))之后達(dá)到理想單機(jī)閾值10。
公式:默認(rèn) coldFactor 為 3算途,即請(qǐng)求 QPS 從 threshold / 3 開(kāi)始塞耕,經(jīng)預(yù)熱時(shí)長(zhǎng)逐漸升至設(shè)定的 QPS 閾值。

這個(gè)好牛逼

5嘴瓤、QPS勻速排隊(duì)

勻速排隊(duì)

勻速排隊(duì)(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式會(huì)嚴(yán)格控制請(qǐng)求通過(guò)的間隔時(shí)間扫外,也即是讓請(qǐng)求以均勻的速度通過(guò),對(duì)應(yīng)的是漏桶算法廓脆。詳細(xì)文檔可以參考 流量控制 - 勻速器模式筛谚,具體的例子可以參見(jiàn) PaceFlowDemo

該方式的作用如下圖所示:

image

這種方式主要用于處理間隔性突發(fā)的流量停忿,例如消息隊(duì)列驾讲。想象一下這樣的場(chǎng)景,在某一秒有大量的請(qǐng)求到來(lái),而接下來(lái)的幾秒則處于空閑狀態(tài)吮铭,我們希望系統(tǒng)能夠在接下來(lái)的空閑期間逐漸處理這些請(qǐng)求时迫,而不是在第一秒直接拒絕多余的請(qǐng)求。

QPS排隊(duì)等待

如上配置表示不管有多少的請(qǐng)求放進(jìn)來(lái)谓晌,一秒鐘只會(huì)處理一個(gè)請(qǐng)求掠拳,超時(shí)時(shí)間設(shè)置為了20s,表示如果這個(gè)請(qǐng)求在20s之后還沒(méi)有被處理就會(huì)報(bào)錯(cuò)纸肉。

六溺欧、Sentinel的服務(wù)降級(jí)

1、簡(jiǎn)介

Sentinel熔斷降級(jí)會(huì)在調(diào)用鏈路中某個(gè)資源出現(xiàn)不穩(wěn)定狀態(tài)時(shí)(例如調(diào)用超時(shí)或異常比例升高)柏肪,對(duì)這個(gè)資源的調(diào)用進(jìn)行限制姐刁,讓請(qǐng)求快速的失敗,當(dāng)資源被降級(jí)時(shí)烦味,在接下來(lái)的降級(jí)時(shí)間窗口之內(nèi)聂使,對(duì)該資源的調(diào)用都自動(dòng)熔斷,而Hystrix則會(huì)有一個(gè)半開(kāi)狀態(tài)拐叉,這是不一樣的岩遗。
RT扇商、異常比例凤瘦、異常數(shù)

image.png

2、RT

平均響應(yīng)時(shí)間 (DEGRADE_GRADE_RT):當(dāng) 1s 內(nèi)持續(xù)進(jìn)入 N 個(gè)請(qǐng)求案铺,對(duì)應(yīng)時(shí)刻的平均響應(yīng)時(shí)間(秒級(jí))均超過(guò)閾值(count蔬芥,以 ms 為單位),那么在接下的時(shí)間窗口(DegradeRule 中的 timeWindow控汉,以 s 為單位)之內(nèi)笔诵,對(duì)這個(gè)方法的調(diào)用都會(huì)自動(dòng)地熔斷(拋出 DegradeException)。注意 Sentinel 默認(rèn)統(tǒng)計(jì)的 RT 上限是 4900 ms姑子,超出此閾值的都會(huì)算作 4900 ms乎婿,若需要變更此上限可以通過(guò)啟動(dòng)配置項(xiàng) -Dcsp.sentinel.statistic.max.rt=xxx 來(lái)配置。

RT降級(jí)規(guī)則

如上圖所示街佑,設(shè)置RT降級(jí)規(guī)則谢翎,RT設(shè)置為200毫秒,時(shí)間窗口設(shè)置為1s沐旨,也就是說(shuō)森逮,如果訪問(wèn)/testB資源進(jìn)入的N個(gè)請(qǐng)求,訪問(wèn)響應(yīng)的時(shí)間都超過(guò)200ms了磁携,那么在這個(gè)時(shí)間窗口期1s內(nèi)褒侧,就會(huì)發(fā)生服務(wù)熔斷。

3、異常比例

異常比例 (DEGRADE_GRADE_EXCEPTION_RATIO):當(dāng)資源的每秒請(qǐng)求量 >= N(可配置)闷供,并且每秒異逞萄耄總數(shù)占通過(guò)量的比值超過(guò)閾值(DegradeRule 中的 count)之后,資源進(jìn)入降級(jí)狀態(tài)这吻,即在接下的時(shí)間窗口(DegradeRule 中的 timeWindow吊档,以 s 為單位)之內(nèi),對(duì)這個(gè)方法的調(diào)用都會(huì)自動(dòng)地返回唾糯。異常比率的閾值范圍是 [0.0, 1.0]怠硼,代表 0% - 100%。

異常比例降級(jí)規(guī)則

如上圖所示移怯,如果一秒鐘內(nèi)有四個(gè)請(qǐng)求訪問(wèn)/testB香璃,50%以上的請(qǐng)求,比如說(shuō)3個(gè)請(qǐng)求訪問(wèn)發(fā)生錯(cuò)誤舟误,就會(huì)在1s的時(shí)間窗口內(nèi)發(fā)生服務(wù)熔斷葡秒。

4、異常數(shù)

異常數(shù) (DEGRADE_GRADE_EXCEPTION_COUNT):當(dāng)資源近 1 分鐘的異常數(shù)目超過(guò)閾值之后會(huì)進(jìn)行熔斷嵌溢。注意由于統(tǒng)計(jì)時(shí)間窗口是分鐘級(jí)別的眯牧,若 timeWindow(時(shí)間窗口) 小于 60s,則結(jié)束熔斷狀態(tài)后仍可能再進(jìn)入熔斷狀態(tài)赖草。所以時(shí)間窗口一定要大于等于一分鐘時(shí)間

異常數(shù)降級(jí)規(guī)則

如上圖所示学少,如果在一分鐘內(nèi),異常數(shù)超過(guò)10個(gè)秧骑,就會(huì)發(fā)生服務(wù)降級(jí)版确。注意時(shí)間窗口一定要大于60s。

七乎折、熱點(diǎn)參數(shù)限流

何為熱點(diǎn)绒疗?熱點(diǎn)即經(jīng)常訪問(wèn)的數(shù)據(jù)。很多時(shí)候我們希望統(tǒng)計(jì)某個(gè)熱點(diǎn)數(shù)據(jù)中訪問(wèn)頻次最高的 Top K 數(shù)據(jù)骂澄,并對(duì)其訪問(wèn)進(jìn)行限制吓蘑。比如:

商品 ID 為參數(shù),統(tǒng)計(jì)一段時(shí)間內(nèi)最常購(gòu)買(mǎi)的商品 ID 并進(jìn)行限制
用戶 ID 為參數(shù)坟冲,針對(duì)一段時(shí)間內(nèi)頻繁訪問(wèn)的用戶 ID 進(jìn)行限制

熱點(diǎn)參數(shù)限流會(huì)統(tǒng)計(jì)傳入?yún)?shù)中的熱點(diǎn)參數(shù)磨镶,并根據(jù)配置的限流閾值與模式,對(duì)包含熱點(diǎn)參數(shù)的資源調(diào)用進(jìn)行限流樱衷。熱點(diǎn)參數(shù)限流可以看做是一種特殊的流量控制棋嘲,僅對(duì)包含熱點(diǎn)參數(shù)的資源調(diào)用生效。

1矩桂、在服務(wù)類新加配置

@GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey", blockHandler = "deal_testHotKey")
    public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
                             @RequestParam(value = "p2", required = false) String p2) {
        return "-----testHotKey";

    }

    public String deal_testHotKey(String p1, String p2, BlockedException e) {
        return "------deal_testHotKey failed";

    }

2沸移、瀏覽器訪問(wèn)

可以訪問(wèn)
也可以訪問(wèn)
對(duì)應(yīng)圖

此時(shí)如果訪問(wèn)這個(gè)路徑http://localhost:8401/testHotKey?p1=a痪伦,因?yàn)樯蠄D進(jìn)行了熱點(diǎn)限流,參數(shù)索引是0雹锣,也就是p1网沾,單機(jī)閾值為1,也就是1s內(nèi)訪問(wèn)超過(guò)1次就會(huì)觸發(fā)熱點(diǎn)限流蕊爵,而這里就是觸發(fā)我們寫(xiě)的兜底方法辉哥。如果沒(méi)有兜底方法的話就會(huì)是一個(gè)很不友好的error界面。而且只要有p1就會(huì)進(jìn)行熱點(diǎn)限流
http://localhost:8401/testHotKey?p1=a會(huì)進(jìn)行熱點(diǎn)限流
http://localhost:8401/testHotKey?p1=a&p2=b會(huì)進(jìn)行熱點(diǎn)限流
http://localhost:8401/testHotKey?p2=b不會(huì)進(jìn)行熱點(diǎn)限流

3攒射、參數(shù)例外項(xiàng)(VIP)

image.png

如上圖所示醋旦,進(jìn)行了參數(shù)例外項(xiàng)的配置,其實(shí)意思就是當(dāng)索引0下標(biāo)對(duì)應(yīng)的值也就是p1会放,當(dāng)他是5時(shí)饲齐,閾值QPS可以達(dá)到200在進(jìn)行熱點(diǎn)限流,而不再是1咧最。相當(dāng)于是給p1=5開(kāi)了一個(gè)vip捂人。參數(shù)類型必須是八大基本類型和String。

4矢沿、系統(tǒng)保護(hù)規(guī)則

image.png

系統(tǒng)保護(hù)規(guī)則是從應(yīng)用級(jí)別的入口流量進(jìn)行控制滥搭,從單臺(tái)機(jī)器的 load、CPU 使用率捣鲸、平均 RT瑟匆、入口 QPS 和并發(fā)線程數(shù)等幾個(gè)維度監(jiān)控應(yīng)用指標(biāo),讓系統(tǒng)盡可能跑在最大吞吐量的同時(shí)保證系統(tǒng)整體的穩(wěn)定性摄狱。系統(tǒng)保護(hù)規(guī)則是應(yīng)用整體維度的脓诡,而不是資源維度的无午,并且僅對(duì)入口流量生效媒役。入口流量指的是進(jìn)入應(yīng)用的流量。

Load 自適應(yīng)(僅對(duì) Linux/Unix-like 機(jī)器生效):系統(tǒng)的 load1 作為啟發(fā)指標(biāo)宪迟,進(jìn)行自適應(yīng)系統(tǒng)保護(hù)酣衷。當(dāng)系統(tǒng) load1 超過(guò)設(shè)定的啟發(fā)值,且系統(tǒng)當(dāng)前的并發(fā)線程數(shù)超過(guò)估算的系統(tǒng)容量時(shí)才會(huì)觸發(fā)系統(tǒng)保護(hù)(BBR 階段)次泽。系統(tǒng)容量由系統(tǒng)的 maxQps * minRt 估算得出穿仪。設(shè)定參考值一般是 CPU cores * 2.5。
CPU usage(1.5.0+ 版本):當(dāng)系統(tǒng) CPU 使用率超過(guò)閾值即觸發(fā)系統(tǒng)保護(hù)(取值范圍 0.0-1.0)意荤,比較靈敏啊片。
平均 RT:當(dāng)單臺(tái)機(jī)器上所有入口流量的平均 RT 達(dá)到閾值即觸發(fā)系統(tǒng)保護(hù),單位是毫秒玖像。
并發(fā)線程數(shù):當(dāng)單臺(tái)機(jī)器上所有入口流量的并發(fā)線程數(shù)達(dá)到閾值即觸發(fā)系統(tǒng)保護(hù)紫谷。
入口 QPS:當(dāng)單臺(tái)機(jī)器上所有入口流量的 QPS 達(dá)到閾值即觸發(fā)系統(tǒng)保護(hù)。

八、@SentinelResource注解

@GetMapping(value = "/byResource")
    @SentinelResource(value = "byResource", blockHandler = "handlerException")
    public String CommonResult() {
        return "success";
    }

    public String handlerException(BlockException e) {
        return "failed" + e;
    }

如上圖所示笤昨,如果每一個(gè)方法都要配置一個(gè)blockHandler祖驱,那么會(huì)造成業(yè)務(wù)和代碼高耦合,且造成代碼冗余瞒窒,所以捺僻,把處理方法提取出來(lái)放到一個(gè)類里面,并且可以在這個(gè)類里面配置多個(gè)方法崇裁。


image.png
@RestController
public class RateLimitController {

    @GetMapping(value = "/extract")
    @SentinelResource(value = "extract", blockHandlerClass = CustomerBlockHandler.class, blockHandler = "Handler1")
    public String HandlerExtract() {
        return "我成功了";
    }
}
public class CustomerBlockHandler {

    public static String Handler1(BlockException e) {
        return "handler1由我來(lái)處理";
    }

    public static String Handler2(BlockException e) {
        return "handler2由我來(lái)處理";
    }
}
image.png

測(cè)試效果

如上圖所示匕坯,這樣就可以避免了代碼的冗余和業(yè)務(wù)的耦合。并且能夠?qū)崿F(xiàn)全局的統(tǒng)一處理方法拔稳,
@SentinelResource注解其他注意:
注意不可以用private注解
注意Sentinel的三個(gè)核心API:
①:sphU定義資源
②:Tracer定義統(tǒng)計(jì)
③:contextUtil定義上下文

九醒颖、服務(wù)熔斷功能

一、環(huán)境預(yù)說(shuō)

客戶端8402和服務(wù)端9003壳炎、9004

9003和9004只有端口號(hào)的差異泞歉,舉例9003配置:
1、module
2匿辩、pom

 <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>

3腰耙、yml

server:
  port: 9003

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848  #配置Nacos地址

management:
  endpoints:
    web:
      exposure:
        include: '*'

4、主啟動(dòng)

@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain9003 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain9003.class, args);
    }
}

5铲球、業(yè)務(wù)類

@RestController
public class PaymentController {
    @Value("${server.port}")
    private String serverPort;

    public static HashMap<Long, Payment> hashMap = new HashMap<>();

    static {
        hashMap.put(1L, new Payment(1L, "dfadfhasdfgjadsf"));
        hashMap.put(2L, new Payment(2L, "nnnnnnnn"));
        hashMap.put(3L, new Payment(3L, "mmmmmmm"));
    }

    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
        Payment payment = hashMap.get(id);
        CommonResult<Payment> result = new CommonResult<>(200, "serverPort:" + serverPort, payment);
        return result;

    }
}

8402客戶端環(huán)境:
1挺庞、module
2、pom

<dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>

3稼病、yml

server:
  port: 8402

spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848  #配置Nacos地址
    sentinel:
      transport:
      #配置Sentinel dashboard地址
      dashboard: localhost:8080
      #默認(rèn)8719端口选侨,假如被占用會(huì)自動(dòng)從8719+1依次掃描
      port: 8719


#消費(fèi)者將要去訪問(wèn)的微服務(wù)名稱(注冊(cè)成功進(jìn)nacos的微服務(wù)提供者)
service-url:
  nacos-user-service: http://nacos-payment-provider

4、主啟動(dòng)

@SpringBootApplication
@EnableDiscoveryClient
public class OrderMain {
    public static void main(String[] args) {
        SpringApplication.run(OrderMain.class, args);
    }
}

5然走、配置類

@Configuration
public class ApplicationContextConfig {

    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

6援制、業(yè)務(wù)類

@RestController
@Slf4j
public class CircleBreakerController {

    public static final String SERVICE_URL = "http://nacos-payment-provider";
    @Resource
    private RestTemplate restTemplate;

    @GetMapping(value = "/consumer/fallback/{id}")
    public CommonResult<Payment> fallBack(@PathVariable("id") Long id) {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);
        if (id == 4) {
            throw new IllegalArgumentException("非法參數(shù)異常");
        } else if (result.getData() == null) {
            throw new NullPointerException("沒(méi)有對(duì)應(yīng)的記錄");
        }
        return result;
    }
}
9004

9003

如上所示,客戶端在訪問(wèn)時(shí)可以實(shí)現(xiàn)輪詢

二芍瑞、然后由業(yè)務(wù)類來(lái)進(jìn)行服務(wù)熔斷的學(xué)習(xí)

運(yùn)用fallback管理程序運(yùn)行時(shí)異常晨仑,如下所示添加一個(gè)fallback方法,就不再是難看的errorpage頁(yè)面拆檬,而是我們自定義的頁(yè)面洪己。

@GetMapping(value = "/consumer/fallback/{id}")
    @SentinelResource(value = "fallback",fallback = "handFallback")
    public CommonResult<Payment> fallBack(@PathVariable("id") Long id) {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);
        if (id == 4) {
            throw new IllegalArgumentException("非法參數(shù)異常");
        } else if (result.getData() == null) {
            throw new NullPointerException("沒(méi)有對(duì)應(yīng)的記錄");
        }
        return result;
    }

    public CommonResult<Payment> handFallback(@PathVariable("id") Long id, Throwable e) {
        Payment payment = new Payment(id, "null");
        return new CommonResult<>(444, "兜底異常" + e.getMessage(), payment);
    }
image.png
image.png

三、fallback只會(huì)管java產(chǎn)生的異常竟贯,blockHandler只會(huì)管Sentinel控制臺(tái)的配置違規(guī)

如下這樣答捕,既配置blockhandler又配置fallback就可以既處理java異常又處理Sentinel配置違規(guī),如果兩個(gè)規(guī)則都違規(guī)時(shí)屑那,則會(huì)進(jìn)入blockHandler的處理拱镐。

@GetMapping(value = "/consumer/fallback/{id}")
//    @SentinelResource(value = "fallback",fallback = "handFallback")
    @SentinelResource(value = "fallback",fallback = "handFallback",blockHandler = "blockHandler")
    public CommonResult<Payment> fallBack(@PathVariable("id") Long id) {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);
        if (id == 4) {
            throw new IllegalArgumentException("非法參數(shù)異常");
        } else if (result.getData() == null) {
            throw new NullPointerException("沒(méi)有對(duì)應(yīng)的記錄");
        }
        return result;
    }

    public CommonResult<Payment> handFallback(@PathVariable("id") Long id, Throwable e) {
        Payment payment = new Payment(id, "null");
        return new CommonResult<>(444, "兜底異常" + e.getMessage(), payment);
    }
    
    public CommonResult<Payment> blockHandler(@PathVariable("id") Long id, BlockException e) {
        Payment payment = new Payment(id, "null");
        return new CommonResult<>(445, "blockhandler異常" + e.getMessage(), payment);
    }

exceptionsToIgnore表示忽略這個(gè)異常晌缘,保證這個(gè)程序先走通,如下所示痢站,這里是個(gè)數(shù)組磷箕,可以加多個(gè)異常VIP

四、Sentinel和OpenFeign

1阵难、修改pom

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

2岳枷、修改yml

#添加激活Sentinel對(duì)Feign支持
feign:
  sentinel:
    enabled: true

3、主啟動(dòng)類添加注解@EnableFeignClients

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderMain8402 {
    public static void main(String[] args) {
        SpringApplication.run(OrderMain8402.class, args);
    }
}

4呜叫、業(yè)務(wù)類
首先是一個(gè)專門(mén)調(diào)用服務(wù)端方法的接口空繁,詳細(xì)看之前OpenFeign的學(xué)習(xí),F(xiàn)eignClient的value對(duì)應(yīng)著服務(wù)類的實(shí)例名朱庆,fallback表示處理降級(jí)的類

@FeignClient(value = "nacos-payment-provider", fallback = PaymentServiceImpl.class)
public interface PaymentService {
    @GetMapping(value = "/paymentSQL/{id}")
    CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
@Component
public class PaymentServiceImpl implements PaymentService {
    @Override
    public CommonResult<Payment> paymentSQL(Long id) {
        return new CommonResult<>(44444, "服務(wù)降級(jí)返回", new Payment(id, "err"));
    }
}

然后在controller就可以直接調(diào)用了盛泡,而不再需要RestTemplate了

@Resource
    private PaymentService paymentService;

    @GetMapping(value = "consumer/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
        return paymentService.paymentSQL(id);
    }

5、測(cè)試


正常調(diào)用測(cè)試

將服務(wù)端停掉

服務(wù)降級(jí)測(cè)試

十娱颊、Sentinel的持久化規(guī)則

痛點(diǎn):每次重啟服務(wù)器傲诵,Sentinel的配置就都沒(méi)有了,導(dǎo)致了每次都要重新配置
解決方法:將限流規(guī)則配置到nacos上面箱硕,只要刷新8401某個(gè)rest地址拴竹,Sentinel的流控規(guī)則就能看到,只要Nacos不刪除配置剧罩,就一直有效栓拜。
詳細(xì)步驟:8401示例
1、pom添加依賴

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

2惠昔、修改yml(yml一定要格式正確幕与,因?yàn)楦袷讲徽_,我的Sentinel持久化一直沒(méi)生效)

server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        #Nacos服務(wù)注冊(cè)中心地址
        server-addr: localhost:8848
    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: localhost:8080
        #默認(rèn)8719端口镇防,假如被占用會(huì)自動(dòng)從8719+1依次掃描
        port: 8719
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: cloudalibaba-sentinel-service
            groupId: DEFAULT_GROUP
            data_type: json
            rule-type: flow

management:
  endpoints:
    web:
      exposure:
        include: '*'

在yml中配置的dataId即對(duì)應(yīng)著在如下Nacos中配置的Data ID啦鸣。

3、在nacos中配置Sentinel流控規(guī)則

配置規(guī)則:
resource:資源名营罢,即限流規(guī)則的作用對(duì)象赏陵;
limitApp:流控針對(duì)的調(diào)用來(lái)源饼齿,若為 default 則不區(qū)分調(diào)用來(lái)源饲漾;
grade:限流閾值類型: 0表示線程數(shù),1表示QPS缕溉;
strategy:流控模式考传,0表示直接,1表示關(guān)聯(lián)证鸥,2表示鏈路僚楞;
controlBehavior:流量控制效果:0快速失敗勤晚、1Warm Up、2排隊(duì)等待泉褐;
clusterMode:是否集群赐写。

配置示例

Sentinel流控規(guī)則生成

這時(shí)Sentinel中就會(huì)一直有我們配置的限流規(guī)則了,但是目前來(lái)看Sentinel的持久化配置比較復(fù)雜膜赃,應(yīng)該是個(gè)半成品挺邀,期待阿里后期繼續(xù)完善。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末跳座,一起剝皮案震驚了整個(gè)濱河市端铛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌疲眷,老刑警劉巖禾蚕,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異狂丝,居然都是意外死亡换淆,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)几颜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)产舞,“玉大人,你說(shuō)我怎么就攤上這事菠剩∫酌ǎ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵具壮,是天一觀的道長(zhǎng)准颓。 經(jīng)常有香客問(wèn)我,道長(zhǎng)棺妓,這世上最難降的妖魔是什么攘已? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮怜跑,結(jié)果婚禮上样勃,老公的妹妹穿的比我還像新娘。我一直安慰自己性芬,他們只是感情好峡眶,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著植锉,像睡著了一般辫樱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上俊庇,一...
    開(kāi)封第一講書(shū)人閱讀 49,185評(píng)論 1 284
  • 那天狮暑,我揣著相機(jī)與錄音鸡挠,去河邊找鬼。 笑死搬男,一個(gè)胖子當(dāng)著我的面吹牛拣展,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播缔逛,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼瞎惫,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了译株?” 一聲冷哼從身側(cè)響起瓜喇,我...
    開(kāi)封第一講書(shū)人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎歉糜,沒(méi)想到半個(gè)月后乘寒,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡匪补,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年伞辛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夯缺。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蚤氏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出踊兜,到底是詐尸還是另有隱情竿滨,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布捏境,位于F島的核電站于游,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏垫言。R本人自食惡果不足惜贰剥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望筷频。 院中可真熱鬧蚌成,春花似錦、人聲如沸凛捏。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)葵袭。三九已至涵妥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間坡锡,已是汗流浹背蓬网。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鹉勒,地道東北人帆锋。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像禽额,于是被迫代替她去往敵國(guó)和親锯厢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容