1. 程式人生 > >Spring Cloud Alibaba | Sentinel:分散式系統的流量防衛兵動態限流規則

Spring Cloud Alibaba | Sentinel:分散式系統的流量防衛兵動態限流規則

Spring Cloud Alibaba | Sentinel:分散式系統的流量防衛兵動態限流規則

前面幾篇文章較為詳細的介紹了Sentinel的使用姿勢,還沒看過的小夥伴可以訪問以下連結檢視:

  • 《Spring Cloud Alibaba | Sentinel:分散式系統的流量防衛兵基礎實戰》
  • 《Spring Cloud Alibaba | Sentinel:分散式系統的流量防衛兵進階實戰》

但是依然無法滿足我們日常的生產需要,其中,非常重要的一點就是限流規則的配置是存在當前應用的記憶體中的,每次我們重啟應用以後,我們在Sentinel控制檯中配置的規則就丟失了,下面,我們就介紹一下Sentinel規則持久化的方式。

Sentinel為我們提供了兩種方式對規則進行修改:

  • 通過 API 直接修改 (loadRules)
  • 通過 DataSource 適配不同資料來源修改

loadRules() 方法只接受記憶體態的規則物件,但更多時候規則儲存在檔案、資料庫或者配置中心當中。DataSource 介面給我們提供了對接任意配置源的能力。相比直接通過 API 修改規則,實現 DataSource 介面是更加可靠的做法。

DataSource 擴充套件常見的實現方式有:

  • 拉模式:客戶端主動向某個規則管理中心定期輪詢拉取規則,這個規則中心可以是 RDBMS、檔案,甚至是 VCS 等。這樣做的方式是簡單,缺點是無法及時獲取變更;
  • 推模式:規則中心統一推送,客戶端通過註冊監聽器的方式時刻監聽變化,比如使用 Nacos、Zookeeper 等配置中心。這種方式有更好的實時性和一致性保證。

Sentinel 目前支援以下資料來源擴充套件:

  • Pull-based: 檔案、Consul (since 1.7.0)
  • Push-based: ZooKeeper, Redis, Nacos, Apollo

這裡,我們重點介紹一下Sentinel基於Nacos實現動態規則。

1. Sentinel基於Nacos動態規則實戰

1.1 建立子工程sentinel_nacos

工程依賴pom.xml如下:

程式碼清單:Alibaba/sentinel-springcloud-high/sentinel_nacos/pom.xml

***

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

1.2 配置檔案application.yml如下:

程式碼清單:Alibaba/sentinel-springcloud-high/sentinel_nacos/src/main/resources/application.yml
***

server:
  port: 10000
spring:
  application:
    name: spring-cloud-sentinel-nacos
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.44.129:8848
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8720
      datasource:
        ds:
          nacos:
            server-addr: 192.168.44.129:8848
            dataId: spring-cloud-sentinel-nacos
            groupId: DEFAULT_GROUP
            rule-type: flow
            namespace: 8282c713-da90-486a-8438-2a5a212ef44f
  • spring.cloud.sentinel.transport.dashboard:Sentinel控制檯的訪問地址。
  • spring.cloud.sentinel.datasource.ds.nacos.server-addr:nacos的訪問地址。
  • spring.cloud.sentinel.datasource.ds.nacos.dataId:nacos中儲存規則的groupId。
  • spring.cloud.sentinel.datasource.ds.nacos.groupId:nacos中儲存規則的dataId。
  • spring.cloud.sentinel.datasource.ds.nacos.rule-type:用來定義儲存的規則型別,不可為空。
  • spring.cloud.sentinel.datasource.ds.nacos.namespace:nacos中儲存規則的namespace。

由於版本迭代關係,本示例中的配置資訊不一定適用於所有版本,可以通過分析DataSourcePropertiesConfigurationNacosDataSourcePropertiesAbstractDataSourceProperties這三個配置來得出具體配置內容,會更為準確。

例如,本示例中的配置來源於NacosDataSourcePropertiesAbstractDataSourceProperties

NacosDataSourceProperties原始碼如下:

public class NacosDataSourceProperties extends AbstractDataSourceProperties {

    private String serverAddr;

    @NotEmpty
    private String groupId = "DEFAULT_GROUP";

    @NotEmpty
    private String dataId;

    private String endpoint;
    private String namespace;
    private String accessKey;
    private String secretKey;

    // 程式碼省略...
}

AbstractDataSourceProperties原始碼如下:

public class AbstractDataSourceProperties {

    @NotEmpty
    private String dataType = "json";
    @NotNull
    private RuleType ruleType;
    private String converterClass;
    @JsonIgnore
    private final String factoryBeanName;
    @JsonIgnore
    private Environment env;
}

筆者這裡僅配置一個不可為空並且沒有預設值的ruleType,有關ruleType的取值可以檢視com.alibaba.cloud.sentinel.datasource.RuleType,這是一個列舉型別。

1.3 建立一個介面測試類HelloController.java如下:

程式碼清單:Alibaba/sentinel-springcloud-high/sentinel_nacos/src/main/java/com/springcloud/sentinel_nacos/controller/HelloController.java
***

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello(HttpServletRequest request) {
        return "Hello, port is: " + request.getLocalPort();
    }
}

1.4 配置Nacos配置中心

配置內容如圖:

注意其中配置的Data ID和Group要和程式中配置的保持一致。格式選擇JSON,填入的內容如下:

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

可以看到上面配置規則是一個數組型別,陣列中的每個物件是針對每一個保護資源的配置物件,每個物件中的屬性解釋如下:

  • resource:資源名,即限流規則的作用物件。
  • limitApp:流控針對的呼叫來源,若為 default 則不區分呼叫來源。
  • grade:限流閾值型別,QPS 或執行緒數模式,0代表根據併發數量來限流,1代表根據QPS來進行流量控制。
  • count:限流閾值
  • strategy:判斷的根據是資源自身,還是根據其它關聯資源 (refResource),還是根據鏈路入口
  • controlBehavior:流控效果(直接拒絕 / 排隊等待 / 慢啟動模式)
  • clusterMode:是否為叢集模式

1.5 測試

正常啟動子工程,開啟瀏覽器訪問幾次http://localhost:10000/hello ,速度快一些可以發現已經限流了,限流後頁面顯示如下:

Blocked by Sentinel (flow limiting)

正面限流配置成功,這時我們開啟Sentinel控制檯,看一下流量規則限制,已經有一條資料了,是我們在Nacos中配置的資料,如圖:

注意:

在Sentinel動態規則整合了Nacos以後,對於修改介面流量控制就有兩個地方了,一個是Sentinel的控制檯,還有一個是Nacos的控制檯。

但是要謹記,在當前版本中,在Sentinel控制檯中修改了規則,將不會同步至Nacos的配置中心,而在Nacos中修改了配置規則,則會通過在客戶端的Listener來是同步Sentinel控制檯。所以,在整合了Nacos做動態規則儲存後需要注意兩點:

  • Sentinel控制檯中修改規則:僅存在於服務的記憶體中,不會修改Nacos中的配置值,重啟後恢復原來的值。
  • Nacos控制檯中修改規則:服務的記憶體中規則會更新,Nacos中持久化規則也會更新,重啟後依然保持。

建議各位堵住最好在Nacos控制檯做規則的修改操作,儘量避免直接在Sentinel控制檯中直接做規則修改。

2. 示例程式碼

Github-示例程式碼

Gitee-示例代