Spring Cloud Alibaba Sentinel 流量衛(wèi)兵

Hi拯田,我是空夜旬昭!

本節(jié)示例代碼在 https://github.com/laolunsi/spring-boot-examples


首先下載 sentinel jar包:https://github.com/alibaba/Sentinel/releases

java -jar sentinel-xx.jar 運(yùn)行著恩,打開(kāi)瀏覽器题山,輸入默認(rèn)地址:http://localhost:8080

參考:如何使用 Sentinel吩案?—— 官方文檔

sentinel 進(jìn)行流量控制有以下流程:

  • 定義資源
  • 定義規(guī)則
  • 檢驗(yàn)規(guī)則是否生效

概念

資源秀又,是 sentinel 的核心概念之一涮帘,可以簡(jiǎn)單的理解為一段代碼拼苍。

sentinel 對(duì)主流的框架都提供了適配,下面以 Spring Cloud 為例,記錄在 Spring Cloud 微服務(wù)架構(gòu)中如何使用 sentinel 進(jìn)行流量控制疮鲫。

資源

分為以下幾種方式:

  • 主流框架的默認(rèn)配置
  • 拋出異常方式定義資源
  • 返回布爾值方式定義資源
  • 注解方式定義資源
  • 異步調(diào)用支持

注解方式定義資源主要用于接口上吆你,對(duì)接口進(jìn)行流量控制,使用的是 @ResourceSentinel 注解俊犯。該注解提供了可選的異常處理和 fallback 配置項(xiàng)妇多。參考:Sentinel 注解支持

源碼:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface SentinelResource {
    // 資源名稱,不能為空
    String value() default "";

    EntryType entryType() default EntryType.OUT;

    int resourceType() default 0;

    // 可選項(xiàng)燕侠,處理 BlockException 的函數(shù)名稱者祖,默認(rèn)在本類中;如果想要指定其他類中的函數(shù)绢彤,需要使用 blockHandlerClass 屬性
    String blockHandler() default "";

    Class<?>[] blockHandlerClass() default {};

    // 可選項(xiàng)七问,fallback 函數(shù)名稱,用于在拋出異常時(shí)提供 fallback 處理邏輯茫舶⌒笛玻可以針對(duì)所有類型的異常。配合 fallbackClass 屬性可以指定其他類中的函數(shù)
    String fallback() default "";

    String defaultFallback() default "";

    Class<?>[] fallbackClass() default {};

    Class<? extends Throwable>[] exceptionsToTrace() default {Throwable.class};

    // 忽略異常饶氏,即 fallback 和 blockHandler 函數(shù)不起作用的異常
    Class<? extends Throwable>[] exceptionsToIgnore() default {};
}

注意:

  • blockHandler 和 fallback 指定的函數(shù)默認(rèn)在本類中坟比,該函數(shù)的返回值類型和參數(shù)順序需與原方法保持一致。blockHandler 對(duì)應(yīng)的函數(shù)可以在最后額外加一個(gè) BlockException 類型的參數(shù)嚷往,fallback 對(duì)應(yīng)的函數(shù)可以再最后額外加一個(gè) Throwable 類型的參數(shù)
  • 使用對(duì)應(yīng)的 blockHandlerClass 和 fallbackClass 可以指定對(duì)應(yīng)函數(shù)所在的類葛账,而不是默認(rèn)的當(dāng)前類。注意皮仁,此時(shí)籍琳,指定的函數(shù)需要是 static 的,否則無(wú)法解析贷祈。

規(guī)則

原理是監(jiān)控應(yīng)用流量的 QPS 或并發(fā)線程數(shù)等指標(biāo)趋急,設(shè)置閾值,避免服務(wù)被瞬時(shí)的高峰流量沖垮势誊。目的是保障高峰流量時(shí)應(yīng)用的高可用性呜达。

目的是防止單個(gè)服務(wù)不可用導(dǎo)致的雪崩現(xiàn)象的發(fā)生,同樣是保障應(yīng)用高可用性的方法之一粟耻。

針對(duì)的是調(diào)用鏈路中不穩(wěn)定的資源查近。

系統(tǒng)保護(hù)規(guī)則從應(yīng)用級(jí)別(而不是資源維度)的入口流量進(jìn)行控制,從單臺(tái)機(jī)器的 load挤忙、CPU 使用率霜威、平均 RT、入口 QPS 和并發(fā)線程等幾個(gè)維度監(jiān)控應(yīng)用指標(biāo)册烈,讓系統(tǒng)盡可能跑在最大吞吐量的同時(shí)保證系統(tǒng)整體的穩(wěn)定性戈泼。

根據(jù)調(diào)用來(lái)源判斷請(qǐng)求是否允許通過(guò)。

看作一種特殊的流量控制規(guī)則,僅對(duì)包含熱點(diǎn)參數(shù)的資源調(diào)用生效大猛。它根據(jù)傳入?yún)?shù)中的熱點(diǎn)參數(shù)扭倾,與配置的限流閾值、模式挽绩,對(duì)包含熱點(diǎn)參數(shù)的資源調(diào)用進(jìn)行限流吆录。

sentinel 還提供了相關(guān) API 用于定制自己的規(guī)則策略。

上面默認(rèn)的規(guī)則分類琼牧,可以通過(guò)代碼定義,也可以使用 dashboard 定義哀卫。

定義規(guī)則可以通過(guò) dashboard巨坊,也可以使用代碼創(chuàng)建。如果想要持久化存儲(chǔ)規(guī)則此改,可以利用 Nacos 等數(shù)據(jù)源趾撵。這一點(diǎn)在后面會(huì)講。


Spring Cloud 整合 Sentinel

參考:spring-cloud-alibaba-sentinel

創(chuàng)建一個(gè) demo 服務(wù)共啃,引入 spring-cloud 中的 sentinel 依賴:

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>0.9.0.RELEASE</version>
        </dependency>

配置:

server:
  port: 8203
spring:
  application:
    name: demo
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8081

可以配置流控占调、降級(jí)、熱點(diǎn)移剪、授權(quán)多種規(guī)則:


注解支持使用參考:注解支持 —— 官方文檔

默認(rèn)情況下是以 url 作為鏈路地址以及資源名的究珊,我們可以在代碼中用 @SentinelResource 注解來(lái)主動(dòng)注明資源的名稱、阻塞處理方法等纵苛。比如:

@RestController
@RequestMapping(value = "test")
@Validated
public class TestAction {

    private static Logger logger = LoggerFactory.getLogger(TestAction.class);

    @SentinelResource(value = "helloTest", blockHandler = "handleEx")
    @GetMapping(value = "hello")
    public String hello(@RequestParam("msg") @NotBlank String msg) {
        logger.info("hellow, " + msg);
        return "hello, " + msg;
    }

    @GetMapping(value = "send")
    @SentinelResource(value = "sendTest", blockHandler = "handleException", blockHandlerClass = BlockHandlerConfig.class)
    public String send(@NotBlank(message = "{required}") String email, @Email(message = "{invalid}") String msg) {
        return "發(fā)消息給:" + email + "剿涮,消息內(nèi)容:" + msg;
    }

    public String handleEx(String msg, BlockException ex) {
        System.out.println("系統(tǒng)錯(cuò)誤:msg=" + msg + ", ex: " + ex);
        return "流量限制,請(qǐng)稍后重試";
    }
}

這里的 helloTest 使用了本類中的 handleEx 方法作為阻塞處理方法攻人。而 sendTest 用 BlockHandlerConfig 類中的 handleException 方法:

public class BlockHandlerConfig {

    public static String handleException(String email, String msg, BlockException exception) {
        return "444, " + exception.getClass().getCanonicalName() + "\t 服務(wù)不可用";
    }
    
}

需要注意的是取试,blockHandle 對(duì)應(yīng)方法的參數(shù)必須與 資源 的參數(shù)保持一致,否則規(guī)則不會(huì)生效怀吻,且會(huì)拋出異常瞬浓。

這里給 helloTest 這個(gè) resource 配置一個(gè)簡(jiǎn)單的流控:

測(cè)試:

快速請(qǐng)求 helloTest 對(duì)應(yīng)的接口,發(fā)現(xiàn)成功請(qǐng)求與限流響應(yīng)交錯(cuò)出現(xiàn)了蓬坡。這表明我們的限流規(guī)則和 blockHandler 生效了猿棉。



規(guī)則持久化

需要注意的是,如果服務(wù)重啟了屑咳,那么這些規(guī)則配置就會(huì)被丟失铺根。其中一個(gè)解決辦法是利用 Nacos 做配置中心,先將規(guī)則定義保存在 Nacos 中乔宿。

sentinel 提供了 file/nacos/zp/apollo 等規(guī)則擴(kuò)展存儲(chǔ)方式位迂。具體參考官方文檔:動(dòng)態(tài)規(guī)則擴(kuò)展

一個(gè)服務(wù)若要使用 Nacos 中的配置作為 sentinel 規(guī)則,除了 Nacos 的依賴外,還需要引入如下依賴:

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>0.9.0.RELEASE</version>
        </dependency>

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

        <!-- 為解決 Caused by: java.lang.ClassNotFoundException: com.alibaba.csp.sentinel.log.CommandCenterLog 引入 -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-transport-simple-http</artifactId>
            <version>1.8.0</version>
        </dependency>

配置:

spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: sentinel-config
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow

nacos 中新建一個(gè) sentinel-config 配置文件掂林,類型是 json臣缀,內(nèi)容比如:

[
    {
         "resource": "helloTest",
         "limitApp": "default",
         "grade":   1,
         "count":   3,
         "strategy": 0,
         "controlBehavior": 0,
         "clusterMode": false    
    }
]

啟動(dòng)后可以看到 sentinel 中出現(xiàn)了這個(gè)規(guī)則。在 nacos 中修改該規(guī)則泻帮,發(fā)現(xiàn) sentinel 那邊同步修改了(反之則不行)


FAQ —— sentinel 部署路徑的問(wèn)題

之前部署 sentinel 的時(shí)候精置,出現(xiàn)過(guò)這樣一個(gè)問(wèn)題:我配置了一個(gè)域名給微服務(wù)平臺(tái)使用,其中的每一個(gè)模板锣杂,如 gateway, zipkin脂倦,sentinel,都是用 nginx 配置的 xxx.com/gateway/xxx 這樣的請(qǐng)求格式來(lái)訪問(wèn)的元莫。

打開(kāi) xxx.com/sentinel赖阻, 是可以看到 dashboard 和每個(gè)服務(wù)的,但是點(diǎn)開(kāi)服務(wù)踱蠢,發(fā)現(xiàn)監(jiān)控?cái)?shù)據(jù)沒(méi)有了火欧,簇點(diǎn)鏈路中每個(gè)地址的 QPS 都是0,點(diǎn)擊新增流控規(guī)則茎截,控制臺(tái)報(bào)了 404 異常苇侵。

在官方倉(cāng)庫(kù)提了這個(gè) issue,有位j叫 jasonjoo2010 的老哥給我解答了一下:

目前dashboard的靜態(tài)部分企锌,并不支持任意子目錄部署的方式榆浓,建議在不改動(dòng)的情況下,使用獨(dú)立域名部署撕攒。

后來(lái)我新增了一個(gè)二級(jí)域名來(lái)專門(mén)訪問(wèn) sentinel哀军,就可以了。

關(guān)于這個(gè)問(wèn)題的詳細(xì)描述在 sentinel 官方倉(cāng)庫(kù)中:https://github.com/alibaba/Sentinel/issues/1804


參考:


最近在系統(tǒng)地學(xué)習(xí) Redis杉适、RabbitMQ、ES 等技術(shù)的知識(shí)柳击,著重關(guān)注原理猿推、底層、并發(fā)等問(wèn)題捌肴,關(guān)于相關(guān)技術(shù)分享后續(xù)會(huì)逐漸發(fā)布出來(lái)蹬叭。歡迎關(guān)注公眾號(hào):猿生物語(yǔ)(ID:JavaApes

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市状知,隨后出現(xiàn)的幾起案子秽五,更是在濱河造成了極大的恐慌,老刑警劉巖饥悴,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坦喘,死亡現(xiàn)場(chǎng)離奇詭異盲再,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)瓣铣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)答朋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人棠笑,你說(shuō)我怎么就攤上這事梦碗。” “怎么了蓖救?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵洪规,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我循捺,道長(zhǎng)斩例,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任巨柒,我火速辦了婚禮,結(jié)果婚禮上柠衍,老公的妹妹穿的比我還像新娘洋满。我一直安慰自己,他們只是感情好珍坊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布牺勾。 她就那樣靜靜地躺著,像睡著了一般阵漏。 火紅的嫁衣襯著肌膚如雪驻民。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,578評(píng)論 1 305
  • 那天履怯,我揣著相機(jī)與錄音回还,去河邊找鬼。 笑死叹洲,一個(gè)胖子當(dāng)著我的面吹牛柠硕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播运提,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蝗柔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了民泵?” 一聲冷哼從身側(cè)響起癣丧,我...
    開(kāi)封第一講書(shū)人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎栈妆,沒(méi)想到半個(gè)月后胁编,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體厢钧,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年掏呼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了坏快。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡憎夷,死狀恐怖莽鸿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情拾给,我是刑警寧澤祥得,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站蒋得,受9級(jí)特大地震影響级及,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜额衙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一饮焦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧窍侧,春花似錦县踢、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至斧账,卻和暖如春谴返,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背咧织。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工嗓袱, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人习绢。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓索抓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親毯炮。 傳聞我的和親對(duì)象是個(gè)殘疾皇子逼肯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

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