1. 程式人生 > >SpringBoot 2.0 + 阿里巴巴 Sentinel 動態限流實戰

SpringBoot 2.0 + 阿里巴巴 Sentinel 動態限流實戰

前言

在從0到1構建分散式秒殺系統和打造十萬博文系統中,限流是不可缺少的一個環節,在系統能承受的範圍內既能減少資源開銷又能防禦惡意攻擊。

在前面的文章中,我們使用了開源工具包 Guava 提供的限流工具類 RateLimiter 和 OpenResty 的 Lua 指令碼分別進行 API 和應用層面的限流。今天,我們來聊聊阿里開源的分散式系統的流量防衛兵 Sentinel。

Sentinel 是什麼?

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

Sentinel 具有以下特徵:

  • 豐富的應用場景:Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的範圍)、訊息削峰填谷、叢集流量控制、實時熔斷下游不可用應用等。

  • 完備的實時監控:Sentinel 同時提供實時的監控功能。您可以在控制檯中看到接入應用的單臺機器秒級資料,甚至 500 臺以下規模的叢集的彙總執行情況。

  • 廣泛的開源生態:Sentinel 提供開箱即用的與其它開源框架/庫的整合模組,例如與 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相應的依賴並進行簡單的配置即可快速地接入 Sentinel。

  • 完善的 SPI 擴充套件點:Sentinel 提供簡單易用、完善的 SPI 擴充套件介面。您可以通過實現擴充套件介面來快速地定製邏輯。例如定製規則管理、適配動態資料來源等。

Sentinel 的主要特性:

Sentinel 的開源生態:

Sentinel 分為兩個部分:

  • 核心庫(Java 客戶端)不依賴任何框架/庫,能夠運行於所有 Java 執行時環境,同時對 Dubbo / Spring Cloud 等框架也有較好的支援。

  • 控制檯(Dashboard)基於 Spring Boot 開發,打包後可以直接執行,不需要額外的 Tomcat 等應用容器。

控制檯配置

Sentinel 控制檯最少應該包含如下功能:

  • 檢視機器列表以及健康情況:收集 Sentinel 客戶端傳送的心跳包,用於判斷機器是否線上。

  • 監控 (單機和叢集聚合):通過 Sentinel 客戶端暴露的監控 API,定期拉取並且聚合應用監控資訊,最終可以實現秒級的實時監控。

  • 規則管理和推送:統一管理推送規則。

  • 鑑權:生產環境中鑑權非常重要。這裡每個開發者需要根據自己的實際情況進行定製。

可以直接從[ release 頁面](https://github.com/alibaba/Sentinel/releases " release 頁面") 下載最新版本的控制檯 jar 包,啟動 Sentinel 控制檯需要 JDK 版本為 1.8 及以上版本。。

啟動指令碼 sentinel.sh:

#!/bin/bash
java -Dsentinel.dashboard.auth.username=admin \
-Dsentinel.dashboard.auth.password=admin \
-Dserver.port=8084 -Dcsp.sentinel.dashboard.server=localhost:8084 \
-Dproject.name=sentinel-dashboard \
-jar sentinel-dashboard-1.6.3.jar &

使用者可以通過如下引數進行配置:

  • -Dsentinel.dashboard.auth.username=admin 用於指定控制檯的登入使用者名稱為 admin;

  • -Dsentinel.dashboard.auth.password=admin 用於指定控制檯的登入密碼為 admin;如果省略這兩個引數,預設使用者和密碼均為 sentinel;

  • -Dserver.servlet.session.timeout=7200 用於指定 Spring Boot 服務端 session 的過期時間,如 7200 表示 7200 秒;60m 表示 60 分鐘,預設為 30 分鐘;

客戶端配置

pom.xml 引入以下依賴:

 <!-- https://blog.52itstyle.vip -->
<parent>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-parent</artifactId>
     <version>2.1.5.RELEASE</version>
     <relativePath/>
</parent>
<dependencies>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
     </dependency>
     <dependency>
         <groupId>com.alibaba.cloud</groupId>
         <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
     </dependency>
</dependencies>
<dependencyManagement>
     <!--注意跟 SpringBoot 保持一致 2.1.x for Spring Boot 2.1.x-->
     <dependencies>
         <dependency>
             <groupId>com.alibaba.cloud</groupId>
             <artifactId>spring-cloud-alibaba-dependencies</artifactId>
             <version>2.1.0.RELEASE</version>
             <type>pom</type>
             <scope>import</scope>
         </dependency>
     </dependencies>
</dependencyManagement>

配置檔案:

# 應用名稱 https://blog.52itstyle.vip
spring.application.name=blog
spring.cloud.sentinel.transport.port=8720
# 測試請替換為自己的地址
spring.cloud.sentinel.transport.dashboard=116.190.247.112:8084

這裡的 spring.cloud.sentinel.transport.port埠配置會在應用對應的機器上啟動一個 Http Server,該 Server 會與 Sentinel 控制檯做互動。比如 Sentinel 控制檯添加了1個限流規則,會把規則資料 push 給這個 Http Server 接收,Http Server 再將規則註冊到 Sentinel 中。

程式碼配置:

/**
  * 博文 https://blog.52itstyle.vip
  */
@RequestMapping("{id}.shtml")
@SentinelResource("blogView")
public String page(@PathVariable("id") Long id, ModelMap model) {
     try{
         Blog blog = blogService.getById(id);
         String key = "blog_"+id;
         Long views = redisUtil.size(key);
         blog.setViews(views+blog.getViews());
         model.addAttribute("blog",blog);
     } catch (Throwable e) {
         return  "error/404";
     }
     return  "article";
}

@SentinelResource 註解用來標識資源是否被限流、降級。上述例子上該註解的屬性 'blogView' 表示資源名。

預設情況,Sentinel 會攔截所有的 Controller 請求,這裡標識資源名,是因為所有的文章都會走這個請求,為了方便統計和流控,這裡自定義資源標識。

更多註解支援,請參考:Sentinel/wiki/註解支援。

訪問客戶端專案,隨便點選幾個頁面,然後登入 Sentinel 控制檯,如果看到以下介面,說明配置成功。

配置限流,搜尋我們剛才配置的資源名稱,選擇流控功能。

輸入閾值引數,為了測試方便,這裡直接輸入2,連續重新整理瀏覽器,如果後臺出現以下錯誤,並伴隨著前臺頁面無法正常顯示說明配置生效。

Caused by: com.alibaba.csp.sentinel.slots.block.flow.FlowException: null

當然,Sentinel 流程功能不僅僅這麼簡單,還支援叢集模式,在終極版十萬博文中,我們可以為叢集中的節點,設定單機均分,也可以設定一個總體的閾值。

生產環境中使用

Sentinel 核心庫目前已可用於生產環境,目前除了阿里巴巴以外,也有多家企業在生產環境中使用它們。

規則管理及推送

原生版本的規則管理通過API 將規則推送至客戶端並直接更新到記憶體中,並不能直接用於生產環境。

不過 Sentinel提供了擴充套件讀資料來源ReadableDataSource,規則中心統一推送,客戶端通過註冊監聽器的方式時刻監聽變化,比如使用 Nacos、Zookeeper 等配置中心。這種方式有更好的實時性和一致性保證。

監控

Sentinel 會記錄資源訪問的秒級資料(若沒有訪問則不進行記錄)並儲存在本地日誌中。Sentinel 控制檯可以通過 Sentinel 客戶端預留的 HTTP API 從秒級監控日誌中拉取監控資料,並進行聚合。

目前 Sentinel 控制檯中監控資料聚合後直接存在記憶體中,未進行持久化,且僅保留最近 5 分鐘的監控資料。若需要監控資料持久化的功能,可以自行擴充套件實現。

注意事項

由於一開始沒有認真讀文件,把控制檯部署到了外網,而客戶端在內網啟動,導致客戶端無法被訪問到,實時鏈路和簇點鏈路資料無法正常顯示。

測試的小夥伴注意了,原始模式下,客戶端和控制檯必須相互被訪問到,客戶端會向控制檯定時傳送心跳請求,控制檯會向客戶端推送規則、拉取流控資料並聚合。

原始碼

https://gitee.com/52itstyle/spring-boot-blog

參考

https://github.com/alibaba/Sentinel