使用 Spring Cloud Alibaba Sentinel 的熔斷降級保護微服務應用

1. 背景

隨著微服務的流行,服務和服務之間的穩(wěn)定性變得越來越重要。以流量為切入點,從流量控制、熔斷降級、系統(tǒng)負載保護等多個維度保護服務的穩(wěn)定性。

1. Sentinel 介紹

Sentinel 提供一個輕量級的開源控制臺,它提供機器發(fā)現(xiàn)以及健康情況管理、監(jiān)控(單機和集群),規(guī)則管理和推送的功能。

1.1 知識

Sentinel 的組成:

  • (1) Sentinel 核心庫, 即基本的類庫的使用。
  • (2) Dashboard 控制臺,即web頁面的使用。

核心庫介紹

本章節(jié)主要說 核心庫 的使用。

使用 Sentinel 來進行資源保護,主要分為幾個步驟:

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

也就是說:

  • 先把可能需要保護的資源定義好(即埋點)
  • 之后再配置規(guī)則,規(guī)則描述了什么方式來保護資源。
  • 聲明了資源,后續(xù)在任何時候靈活地定義各種流量控制規(guī)則。

資源

資源:可以是指一個服務,一個服務里的方法,或者是一段代碼。寫代碼時,考慮某段代碼是否需要保護,如果需要就將之定義為一個資源。

定義資源的方式

sentinel 支持都多種方式來定義資源,常見的有:

  • 方式一:整合到常見的主流框架,比如 Web Servlet、Dubbo、Spring Cloud
  • 方式二:拋出異常的方式,使用 SphU 這個類的 try-catch 方式
  • 方式三:返回布爾值方式定義資源,使用 SphO 提供 if-else 風格的 API
  • 方式四:注解方式定義資源,使用 @SentinelResource 注解 。
  • 方式五:異步調用支持,使用 SphU.asyncEntry 異步方法。

示例有:
拋出異常的方式 來定義資源
使用 SphU 這個類的 try-catch 風格的 API。當“資源”發(fā)生了限流之后會拋出 BlockException,然后捕捉異常進行限流之后的邏輯處理。

示例代碼如下:

try (Entry entry = SphU.entry("resourceName")) {
  // 被保護的業(yè)務邏輯
  // do something here...
} catch (BlockException ex) {
  // 資源訪問阻止,被限流或被降級
  // 在此處進行相應的處理操作
}

規(guī)則

Sentinel 支持以下幾種規(guī)則:

  • 流量控制規(guī)則
  • 熔斷降級規(guī)則
  • 系統(tǒng)保護規(guī)則
  • 來源訪問控制規(guī)則
  • 熱點參數(shù)規(guī)則

流量控制規(guī)則(FlowRule)
支持 QPS 模式(1)或并發(fā)線程數(shù)模式(0)。

熔斷降級規(guī)則(DegradeRule)
熔斷策略,支持慢調用比例/異常比例/異常數(shù)策略

系統(tǒng)保護規(guī)則 (SystemRule)
結合應用的 Load、CPU 使用率、總體平均 RT、入口 QPS 和并發(fā)線程數(shù)等幾個維度的監(jiān)控指標,通過自適應的流控策略,讓系統(tǒng)的入口流量和系統(tǒng)的負載達到一個平衡

來源訪問控制規(guī)則 (AuthorityRule)
即黑名單,白名單規(guī)則。

規(guī)則的持久化
建議和 nacos 一起使用,方法見本文后面章節(jié)。

1.2 在service層使用 Sentinel

一般java web 項目都會有 controller 層, service 層,dao層,我們要在 service 層使用的是可以這么做。

(1)添加依賴

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

(2) 在服務層加注解:

@Service
public class TestService {

    @SentinelResource(value = "sayHello")
    public String sayHello(String name) {
        return "Hello, " + name;
    }
}

@SentinelResource 注解用來標識資源是否被限流、降級。上述例子上該注解的屬性 value 指示了一個資源名稱。

@SentinelResource 還提供了其它額外的屬性如 blockHandler,blockHandlerClass,fallback 用于表示限流或降級的操作

一般我們需要實現(xiàn)一個降級后的處理,比如上面的 fallback 指示一個降級后字符串返回值告知觸發(fā)了熔斷降級。

另外,Sentinel 控制臺提供一個輕量級的控制臺,它提供機器發(fā)現(xiàn)、單機資源實時監(jiān)控、集群資源匯總,以及規(guī)則管理的功能。您只需要對應用進行簡單的配置,就可以使用這些功能。我們在后面用一個章節(jié)來介紹它。

1.3 和 Feign 一起使用

Sentinel 適配了組件。

(1) 先引入 spring-cloud-starter-alibaba-sentinel 的依賴
(2) 再引入feign依賴
引入 spring-cloud-starter-openfeign 依賴**,使 Sentinel starter 中的自動化配置類生效:

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

(3) 配置文件打開
配置文件打開 Sentinel 對 Feign 的支持:

feign.sentinel.enabled=true

示例說明
比如下面的示例中你要了解的:

  • 1.正常的業(yè)務調用: /echo/{str}。
    1. 熔斷后的異常處理,指定了 fallback 處理,并返回 "echo fallback" 字符串。

詳細示例:

@FeignClient(name = "service-provider", fallback = EchoServiceFallback.class, configuration = FeignConfiguration.class)
public interface EchoService {
    @RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)
    String echo(@PathVariable("str") String str);
}

class FeignConfiguration {
    @Bean
    public EchoServiceFallback echoServiceFallback() {
        return new EchoServiceFallback();
    }
}

class EchoServiceFallback implements EchoService {
    @Override
    public String echo(@PathVariable("str") String str) {
        return "echo fallback";
    }
}

1.4 和 RestTemplate 一起使用

支持對 RestTemplate 的服務調用使用 Sentinel 進行保護,加上 @SentinelRestTemplate 注解。

@Bean
@SentinelRestTemplate(blockHandler = "handleException", blockHandlerClass = ExceptionUtil.class)
public RestTemplate restTemplate() {
    return new RestTemplate();
}

說明:@SentinelRestTemplate 注解的屬性
@SentinelRestTemplate 注解的屬性支持限流(blockHandler, blockHandlerClass)和降級(fallback, fallbackClass)的處理。

比如上面的示例指示了 ExceptionUtil.handleException 是熔斷降級后的異常處理方法,該方面用明確的方法簽名格式,如下:

public class ExceptionUtil {
    public static ClientHttpResponse handleException(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException exception) {
        ...
    }
}

方法返回值提供了 SentinelClientHttpResponse 用于構造返回信息。

注意
應用啟動的時候會檢查 @SentinelRestTemplate 注解對應的限流或降級方法是否存在,如不存在會拋出異常

實際項目中也會在網(wǎng)關層使用,見下一章節(jié)。

2. 在 Spring Cloud Gateway 網(wǎng)關中使用

可以結合 Spring Cloud Gateway 一起使用。

  • (1) 添加 spring-cloud-alibaba-sentinel-gateway 依賴。
  • (2) 添加 spring-cloud-starter-gateway 依賴
    來讓 spring-cloud-alibaba-sentinel-gateway 模塊里的 Spring Cloud Gateway 自動化配置類生效:
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
  • (3) 配置文件
    指定 spring.cloud.sentinel.filter.enabled 為 false

注意
網(wǎng)關流控規(guī)則數(shù)據(jù)源類型是 gw-flow,若將網(wǎng)關流控規(guī)則數(shù)據(jù)源指定為 flow 則不生效。

支持兩種資源標識維度的限流
Sentinel 提供的 Spring Cloud Gateway 的適配模塊可以提供兩種資源維度的限流:

  • routeId:即在 gateway 中的路由 routeId。
  • 自定義分組的名稱:可以利用 API 來自定義一些分組名,將URL歸類在一個組下。
  • 默認不支持 URL 粒度

3. sentinel 的控制臺

3.1 Sentinel 控制臺包含如下功能:

  • 查看機器列表以及健康情況:收集 Sentinel 客戶端發(fā)送的心跳包,用于判斷機器是否在線。
  • 監(jiān)控 (單機和集群聚合):通過 Sentinel 客戶端暴露的監(jiān)控 API,定期拉取并且聚合應用監(jiān)控信息,最終可以實現(xiàn)秒級的實時監(jiān)控。
  • 規(guī)則管理和推送:統(tǒng)一管理推送規(guī)則。
  • 鑒權:生產(chǎn)環(huán)境中鑒權非常重要。這里每個開發(fā)者需要根據(jù)自己的實際情況進行定制。

3.2. 啟動 sentinel 的控制臺

下載最新版本的控制臺 jar 包
可以從這個 release 頁面 下載。

命令行啟動

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.2.jar  -Dsentinel.dashboard.auth.username=sentinel -Dsentinel.dashboard.auth.password=123456

說明:

  • -Dserver.port=8080 用于指定 Sentinel 控制臺端口為 8080,瀏覽器從這個端訪問。打開頁面,默認用戶名和密碼都是 sentinel。

3.3. 規(guī)則管理

管理和新增規(guī)則
打開 http://localhost:8080
您可以在 控制臺web頁 配置修改規(guī)則,進行規(guī)則管理。

image.png

點擊新增規(guī)則按鈕,如下:


image.png

規(guī)則的存儲
默認是存儲在內(nèi)存的,應用重啟之后該規(guī)則會丟失。建議通過一些配置來使用外部存儲方式來保存。建議結合 nacos 動態(tài)實時的刷新規(guī)則。

3.4. 規(guī)則推送

規(guī)則推送分為 3 種模式,包括:

  • 原始模式
  • Pull 模式
  • Push 模式"。

原始模式

通過 API 將規(guī)則推送至客戶端并直接更新到內(nèi)存中, 圖例:

                             ------> sentinel 客戶端1
Sentinel                     ------> sentinel 客戶端2
Dashboard
                             ------> sentinel 客戶端3

好處: 簡單,無依賴;
壞處: 應用重啟規(guī)則就會消失,不能用于生產(chǎn)環(huán)境

Pull模式

在客戶端注冊一個本地文件數(shù)據(jù)源:收到控制臺推送的規(guī)則時,Sentinel 會先更新到內(nèi)存,然后將規(guī)則寫入到文件中。

本地文件數(shù)據(jù)源會定時輪詢文件的變更,讀取規(guī)則。

這樣我們既可以在應用本地直接修改文件來更新規(guī)則,也可以通過 Sentinel 控制臺推送規(guī)則。

以本地文件數(shù)據(jù)源為例,過程如下圖所示:

                                      /---------- 在內(nèi)存中更新規(guī)則(規(guī)則緩存)
                                     /
Sentinel        ----->   Sentinel客戶端     ----> 將規(guī)則寫入本地文件   ----> 本地文件
Dashboard

好處:簡單,不引入新的依賴
壞處:無法保證監(jiān)控數(shù)據(jù)的一致性

Push模式

Sentinel 控制臺 的規(guī)則到 統(tǒng)一配置中心(比如nacos),再到各個 客戶端。

即: Sentinel 控制臺 → 配置中心 → Sentinel 數(shù)據(jù)源 → Sentinel

圖例:

                       nacos
             (1)    /        \
                   /           \    (2)
                 /               \
Sentinel                          |----    sentinel 客戶端1
Dashboard                         |----    sentinel 客戶端2

生產(chǎn)環(huán)境建議使用 PUSH 模式,改造方法見下一章節(jié)。

4. 和 nacos 集成

4.1 介紹

默認情況下,規(guī)則是存儲在內(nèi)存的,重啟后就沒了。因此在生產(chǎn)環(huán)境建議使用nacos 集成來使用。分成兩個步驟:

  • (1) 在sentinel dashboard 控制臺的web管理頁面創(chuàng)建規(guī)則,并將規(guī)則存儲到nacs。需要改造sentinel 控制臺。
  • (2) 客戶端應用獲得從 nacos 推送(PUSH)而來的 “限流的配置規(guī)則”,并加載到sentinel中。

即:在sentinel dashboard 的web頁設置限流規(guī)則 ---> 規(guī)則存儲到 nacos ---> 再推送到客戶端應用

4.2 改造 sentinel 控制臺

改造的目標是:改造 sentinel 控制臺,使得在控制臺的web頁修改的規(guī)則保存到nacos中去。
具體改造方法:略。
有同學已經(jīng)改造好的在這里:https://gitee.com/schonglin/sentinel-nacos

4.3 配置客戶端,讀nacos數(shù)據(jù)源。

實現(xiàn)的目標是:從nacos 讀取規(guī)則并應用到客戶端應用中。

4.3.1 修改客戶端服務的配置文件,添加一個數(shù)據(jù)源

下面的示例中,我添加了一個 sentinel 的數(shù)據(jù)源 ds2, 指定了 nacos服務的地址,data-id 配置文件名,規(guī)則是 rule-type 限流類型。

spring:
  application:
    name: business
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080 # 指定控制臺地址和端口
        port: 8721 # 這個端口和 Sentinel dashborad 做交互
      datasource:
        # 指定一個用于流控規(guī)則的數(shù)據(jù)源(來自nacos)
        ds2:
          nacos:
            server-addr: ${spring.cloud.nacos.discovery.server-addr}
            data-id: ${spring.application.name}-flow-rules  # 比如流控的規(guī)則是 {appName}-flow-rules
            group-id: SENTINEL_GROUP # 指定的一個分組名
            data-type: json
            rule-type: flow

4.3.2 在nacos中添加一個限流的配置文件,和數(shù)據(jù)源名稱一致

我在nacos中添加一個限流的配置文件,名字叫做${spring.application.name}-sentinel-flow,它的格式和上面 data-id 要對應上。

[
    {
        "resource": "/hello",
        "limitApp": "default",
        "grade": 1,
        "count": 6,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]

上面的配置內(nèi)容說明:

  • resource:資源名
  • limitApp:調用來源, default 則不區(qū)分調用來源
  • grade:限流閾值類型(QPS 或并發(fā)線程數(shù));0代表根據(jù)并發(fā)數(shù)量來限流,1代表根據(jù)QPS來進行流量控制
  • count:限流閾值,和上面的類型相關
  • strategy:調用關系限流策略
  • controlBehavior:流量控制效果(直接拒絕、Warm Up、勻速排隊)
  • clusterMode:是否為集群模式

訪問幾次接口后,就可以在Sentinel Dashboard 中看到在nacos中配置的規(guī)則信息,重啟后也可以再次重nacos獲取到配置好的規(guī)則。

我的示例demo 見: https://github.com/vir56k/java_demo/tree/master/sentinel/sentineldemo3 配合 改造后支持nacos的sentinel 來使用。

5. 參考

Sentinel 控制臺
https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0
https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel
https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81
https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel
https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8
https://github.com/alibaba/Sentinel/wiki/%E5%9C%A8%E7%94%9F%E4%BA%A7%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Sentinel
https://www.cnblogs.com/gyli20170901/p/11279576.html
https://github.com/alibaba/Sentinel/wiki/Sentinel-%E6%8E%A7%E5%88%B6%E5%8F%B0%EF%BC%88%E9%9B%86%E7%BE%A4%E6%B5%81%E6%8E%A7%E7%AE%A1%E7%90%86%EF%BC%89#%E8%A7%84%E5%88%99%E9%85%8D%E7%BD%AE
https://blog.csdn.net/qq_38723394/article/details/108991518

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

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