【Sentinel】sentinel 集成 apollo 最佳實踐

【Sentinel】sentinel 集成 apollo 最佳實踐

sentinel

前言

  在 sentinel 的控制檯設置的規則信息默認都是存在內存當中的。所以無論你是重啓了 sentinel 的客戶端還是 sentinel 的控制檯。你所設置的規則都會丟失。如果想要 sentinel 在線上環境使用,要麼花錢用阿里雲上的付費版本,要麼自己去實現規則的持久化,如果你或你所在的公司不差錢,那麼關掉這篇文章,直接用付費版吧,省掉了一大堆坑要踩。或者你是一個特立獨行的人,那麼我們接着往下說。
  首先說一下寫這篇文章的原因,因爲真得在與 apllo 集成時,踩坑踩到懷疑人生。另一點是,找了一大堆關於集成的 apollo 的文章,都清一色的都是仿照官方給的限流規則的 DEMO 做的。 但是 sentinel 規則還有熔斷規則、參數限流、系統限流、黑白名單等很多規則,每個規則還有細節上的不一致,這些都沒有提,還有一些客戶端的坑就更沒有了。踩了這麼多坑,有了一點心得與體會,梳理與此,希望能幫助到讀者。

拉取 sentinel 控制檯源碼進行修改

  因爲修改內容過多,本文不會詳述,下面的截圖是所有修改內容,並且因爲寫這篇文章時,1.7版本在 master 開發,有大量快照版本。所以是切到當前穩定的 1.6 分支進行修改的。我已經 fork sentinel 到我的 github,下面是修改的內容 地址

修改點1:實現所有規則的拉取與推送接口

  添加與實現了所有的規則的 Provider 與 Publisher 的配置拉取的與推送。

修改點2:修改控制檯使用的規則操作 api

規則在控制檯的操作 controller 進行大量改造。

修改點3:修改 xxEntity

  最後一點也是最坑的修改了大量的 xxEntity 類,這些類是規則的實體類,本身沒什麼,源碼是直接 json 化保存的,但是用於客戶端集成的 spring-cloud-alibaba 使用了 json 校驗,如果 apollo 保存的 json 與客戶端的實體類有一丁點不一樣就報 convert 0 rules but there are 1 rules from datasource . RuleCLass: FlowRule 。 是不是覺得很摸不着頭腦,這報錯跟 json 格式轉換錯誤有什麼,下面是 spring-cloud-alibaba json 轉換的代碼。

  寫這段代碼的老哥,把這個異常吃了,並補上了一個 // won't be happen 的註釋,你能理解我當時被這個報錯坑的死去活來,後來發現是這裏的問題嗎?後來在 github 上找到兩個同樣的問題問題1問題2,按照方法把 xxEntity 中用不到的字段全部加上 @JSONField(serialize = false) 解決。

修改點4:抽離配置使得可以在啓動的時傳入

  添加的配置在下面

使用修改的控制檯版本

  1. 你可以fork sentinel 官方代碼按上述的自行修改,然後打包
  2. 你可以拉取我 fork 的 sentinel 代碼下來直接打包
  3. 你可以使用我已經打好的包 地址

自定義配置

配置名稱 是否必填 默認值 作用
env DEV 指定 apollo 使用的環境
app.id sentinel-apollo 指定保存 sentinel 規則的 apollo 應用 ID
cluster.name default 指定保存 sentinel 使用的 apollo 集羣
namespace.name application 指定保存 sentinel 使用的 apollo 命名空間
modify.user
apollo 控制檯顯示的修改人賬號,此賬號務必要有此應用的權限
modify.comment modify by sentinel-dashboard apollo 控制檯顯示的修改備註
release.user
apollo 控制檯顯示的發佈人賬號,此賬號務必要有此應用的權限
release.comment release by sentinel-dashboard apollo 控制檯顯示的發佈備註
apollo.portal.url
 apollo 控制檯的地址
apollo.application.token
指定保存 sentinel 規則的 apollo 應用 openapi 的 token
authority.key.suffix authority 認證規則保存在 apollo 中的 key 的後綴
degrade.key.suffix degrade 熔斷規則保存在 apollo 中的 key 的後綴
flow.key.suffix flow 限流規則保存在 apollo 中的 key 的後綴
param.key.suffix param_flow 參數限流規則保存在 apollo 中的 key 的後綴
system.key.suffix system 系統限流規則保存在 apollo 中的 key 的後綴
auth.username sentinel sentinel 控制檯的登錄用戶名
auth.password sentinel sentinel 控制檯的登錄密碼
server.port 8080 sentinel 控制檯的啓動端口

Apollo 配置

創建用於保存 sentinel 的項目

  1. 點擊創建項目按鈕
  2. 輸入項目信息
    1. 應用 ID 對應 上面表格中的 app.id
    2. 應用負責人 對應 上面表格中的 modify.userrelease.user
  3. 創建一個公共命名空間
    1. 點擊右下角添加 Namespace 按鈕
    2. 創建 Namespace
      1. 名稱對應上面表格中的 namespace.name,注意名稱是要包含部門名的,這裏脫敏了
      2. 類型一定要選擇 public ,原因後面會說
  4. 發佈 Namespace
    1. 私有的空間是不能被繼承的,application 沒有用,可以刪除
      1. 這裏的用意是我們獨立出一個單獨的用於保存規則的 apollo 應用,因爲是公共的,所以其它apollo 應用可以繼承,這樣對於已經集成 apollo 的項目來說,改動最小
      2. 注意紅色的提示,我們建的公共空間要首先發布一次,否則 api 無法訪問到
  5. 創建此項目的開放平臺授權
    1. 點擊右上角的開放平臺授權管理
    2. 創建應用
      1. 第三方應用 ID 就是你上面創建的項目的 appId
      2. 第三方應用名稱 隨便寫
    3. 賦權
      1. token 你點擊創建應用後自動生成的
      2. 被管理的 Appid 就是你上面創建的項目的 appId
      3. 授權類型 一定要選 App

spring boot 集成 sentinel

源碼地址

引入依賴

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>0.9.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-apollo</artifactId>
            <version>1.5.2</version>
        </dependency>

測試 controller

package cn.coder4j.study.example.sentinel;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author buhao
 * @version TestController.java, v 0.1 2019-09-19 20:53 buhao
 */
@RequestMapping("/test")
@Controller
public class TestController {

    /**
     * 沒有註解通過自適應的限流
     * @return
     */
    @GetMapping("/flowRule")
    @ResponseBody
    public String flowRule(){
        return "success";
    }

    /**
     * 通過手動註解的限流
     * @return
     */
    @GetMapping("/flowRuleWithAnno")
    @ResponseBody
    @SentinelResource("flowRuleWithAnno")
    public String flowRuleWithAnno(){
        return "success";
    }

    /**
     * 參數限流規則測試
     * @param param
     * @return
     */
    @GetMapping("/paramFlowRule")
    @ResponseBody
    @SentinelResource("paramFlowRule")
    public String paramFlowRule(String param){
        return "success";
    }

    /**
     * 熔斷規則測試
     * @return
     */
    @GetMapping("/degradeRule")
    @ResponseBody
    @SentinelResource("degradeRule")
    public String degradeRule(){
        throw new RuntimeException("服務器異常");
    }
}

配置 application.yml

apollo:
  bootstrap:
    enabled: true # 開啓 apollo
  meta: xxx       # 指定 apollo 註冊地址
app:
  id: sentinel-apollo  # 指定規則項目在 apollo 的app.id,要與 sentinel 控制檯啓動參數一致
spring:
  application:
    name: study-sentinel-example  # 應用名稱,不同項目要唯一,會把他做爲規則 Key 的前綴
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8989  # sentinel 控制檯的地址
      datasource:
        ds1:
          apollo:
            namespace-name: {部門名}.sentinel-rule  # 保存規則的 apollo 應用的公共 namespace, 要與 sentinel 控制檯啓動參數一致
            rule-type: flow   # 指定該數據源是限流規則
            flow-rules-key: ${spring.application.name}-${spring.cloud.sentinel.datasource.ds1.apollo.rule-type} # 指定該規則在 apollo 應用中 key 名稱
        ds2:
          apollo:
            namespace-name: {部門名}.sentinel-rule
            rule-type: degrade # 指定該數據源是熔斷規則
            flow-rules-key: ${spring.application.name}-${spring.cloud.sentinel.datasource.ds2.apollo.rule-type} # 指定該規則在 apollo 應用中 key 名稱
        ds3:
          apollo:
            namespace-name: {部門名}.sentinel-rule
            rule-type: param_flow # 指定該數據源是參數限流規則
            flow-rules-key: ${spring.application.name}-${spring.cloud.sentinel.datasource.ds3.apollo.rule-type} # 指定該規則在 apollo 應用中 key 名稱
        ds4:
          apollo:
            namespace-name: {部門名}.sentinel-rule
            rule-type: system  # 指定該數據源是系統限流規則
            flow-rules-key: ${spring.application.name}-${spring.cloud.sentinel.datasource.ds4.apollo.rule-type} # 指定該規則在 apollo 應用中 key 名稱
        ds5:
          apollo:
            namespace-name: {部門名}.sentinel-rule
            rule-type: authority # 指定該數據源是認證限流(黑白名單)規則
            flow-rules-key: ${spring.application.name}-${spring.cloud.sentinel.datasource.ds5.apollo.rule-type} # 指定該規則在 apollo 應用中 key 名稱

sentinel 控制檯配置

  1. 第一次啓動時 sentinel 是沒有應用數據,只要請求幾次你應用的接口就可以了
  2. 請求之後可以看到我們的應用在右側列表了
  3. 首先點擊簇點監控,如果是空白的話說明,接口還沒有被請求過,通過上面提供的 jmeter 腳本,可以快速訪問所有接口,訪問後如下圖所示
    1. 可以看到除了我們手動通過註解定義的資源名,還多了一些是通過我們的 controller 路徑的資源名,這些都是我們客戶端集成 spring-cloud-starter-alibaba-sentinel 包後,自動適配的。這兩種其實在使用上有區別的
      1. 自動適配的限流後會返回 Blocked by Sentinel (flow limiting)
      2. 通過註解的是會拋出 UndeclaredThrowableException 異常,我們可以通過 文章 說的方法轉成我們想的限流異常處理。
    2. 右邊的操作就是添加各種規則,這裏修改後會實時同步到客戶端並同步保存到 apollo

jmeter 配置

  jmeter 是用於測試與驗證規則使用的,因爲可以設置線程數,所以可以很好的測試限流情況。測試腳本下載

  1. 線程組要把線程設置成 100,方便後面的統計,另外爲了在一秒內執行完,Ramp-Up 時間設爲0
  2. 請求默認值就是填寫你本地的啓的測試項目的地址
  3. xx 規則填寫測試接口地址,參數限流因爲要做對照實驗所以寫了兩個
  4. 查看結果樹可以看到你每次請求的內容與結果
  5. 可以看到上張圖片內有紅色的有綠色的,紅色說明斷言失敗,綠色說明斷言成功,斷言的內容就是包含 success
  6. 聚合統計,這個可以統計出100個線程請求後的總體結果,我們只要看 Error% 的失敗率就可以了。圖中可以看到除了熔斷限流,其它限流失敗率是 0

測試步驟

  1. 在簇點鏈路中找到 /test/flowRule,並點擊流控按鈕
  2. 單機閾值填入 10,點擊新增
  3. 新增後會跳轉到流程規則頁面
  4. 運行jemter,可以看到失敗率爲90%,這代表你的限流成功了
    1. 上面說了失敗是因爲斷言沒有成功,也就是說沒有返回 success,那他現在返回的是什麼呢?
    2. 察看結果樹,隨便找一條紅包的記錄,看響應數量
    3. 可以看到返回的是 "Blocked by Sentinel (flow limiting)",這個就是集成後配置的限流頁面的返回值,可以通過 spring.cloud.sentinel.servlet.block-page 指定成你自己的頁面
  5. 另外打開 apollo 可以看到,多了一個規則,這就是你剛剛添加的限流規則

歡迎關注我的公衆號「KIWI的碎碎念」,也可以收藏 我的博客

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