Sentinel分布式系統的流量防衛兵


Sentinel 是什么?官網:https://github.com/alibaba/Sentinel/wiki/介紹

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

Sentinel 具有以下特征:

  • 豐富的應用場景:Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的范圍)、消息削峰填谷、集群流量控制、實時熔斷下游不可用應用等。
  • 完備的實時監控:Sentinel 同時提供實時的監控功能。您可以在控制台中看到接入應用的單台機器秒級數據,甚至 500 台以下規模的集群的匯總運行情況。
  • 廣泛的開源生態:Sentinel 提供開箱即用的與其它開源框架/庫的整合模塊,例如與 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相應的依賴並進行簡單的配置即可快速地接入 Sentinel。
  • 完善的 SPI 擴展點:Sentinel 提供簡單易用、完善的 SPI 擴展接口。您可以通過實現擴展接口來快速地定制邏輯。例如定制規則管理、適配動態數據源等。

Sentinel 的主要特性:

Sentinel 基本概念:

資源:

  資源是 Sentinel 的關鍵概念。它可以是 Java 應用程序中的任何內容,例如,由應用程序提供的服務,或由應用程序調用的其它應用提供的服務,甚至可以是一段代碼。在接下來的文檔中,我們都會用資源來描述代碼塊。只要通過 Sentinel API 定義的代碼,就是資源,能夠被 Sentinel 保護起來。大部分情況下,可以使用方法簽名,URL,甚至服務名稱作為資源名來標示資源。

規則:

  圍繞資源的實時狀態設定的規則,可以包括流量控制規則、熔斷降級規則以及系統保護規則。所有規則可以動態實時調整。

Sentinel 功能和設計理念:

流量控制:

  流量控制在網絡傳輸中是一個常用的概念,它用於調整網絡包的發送數據。然而,從系統穩定性角度考慮,在處理請求的速度上,也有非常多的講究。任意時間到來的請求往往是隨機不可控的,而系統的處理能力是有限的。我們需要根據系統的處理能力對流量進行控制。Sentinel 作為一個調配器,可以根據需要把隨機的請求調整成合適的形狀,如下圖所示:

流量控制設計理念,流量控制有以下幾個角度:

  • 資源的調用關系,例如資源的調用鏈路,資源和資源之間的關系;
  • 運行指標,例如 QPS、線程池、系統負載等;
  • 控制的效果,例如直接限流、冷啟動、排隊等。

Sentinel 的設計理念是讓您自由選擇控制的角度,並進行靈活組合,從而達到想要的效果。

熔斷降級:

  除了流量控制以外,降低調用鏈路中的不穩定資源也是 Sentinel 的使命之一。由於調用關系的復雜性,如果調用鏈路中的某個資源出現了不穩定,最終會導致請求發生堆積。Sentinel 和 Hystrix 的原則是一致的: 當檢測到調用鏈路中某個資源出現不穩定的表現,例如請求響應時間長或異常比例升高的時候,則對這個資源的調用進行限制,讓請求快速失敗,避免影響到其它的資源而導致級聯故障。

熔斷降級設計理念:

  在限制的手段上,Sentinel 和 Hystrix 采取了完全不一樣的方法。Hystrix 通過 線程池隔離 的方式,來對依賴(在 Sentinel 的概念中對應 資源)進行了隔離。這樣做的好處是資源和資源之間做到了最徹底的隔離。缺點是除了增加了線程切換的成本(過多的線程池導致線程數目過多),還需要預先給各個資源做線程池大小的分配。

Sentinel 對這個問題采取了兩種手段:

  1. 通過並發線程數進行限制 : 和資源池隔離的方法不同,Sentinel 通過限制資源並發線程的數量,來減少不穩定資源對其它資源的影響。這樣不但沒有線程切換的損耗,也不需要您預先分配線程池的大小。當某個資源出現不穩定的情況下,例如響應時間變長,對資源的直接影響就是會造成線程數的逐步堆積。當線程數在特定資源上堆積到一定的數量之后,對該資源的新請求就會被拒絕。堆積的線程完成任務后才開始繼續接收請求。
  2. 通過響應時間對資源進行降級 : 除了對並發線程數進行控制以外,Sentinel 還可以通過響應時間來快速降級不穩定的資源。當依賴的資源出現響應時間過長后,所有對該資源的訪問都會被直接拒絕,直到過了指定的時間窗口之后才重新恢復。

系統負載保護:

  Sentinel 同時提供系統維度的自適應保護能力。防止雪崩,是系統防護中重要的一環。當系統負載較高的時候,如果還持續讓請求進入,可能會導致系統崩潰,無法響應。在集群環境下,網絡負載均衡會把本應這台機器承載的流量轉發到其它的機器上去。如果這個時候其它的機器也處在一個邊緣狀態的時候,這個增加的流量就會導致這台機器也崩潰,最后導致整個集群不可用。針對這個情況,Sentinel 提供了對應的保護機制,讓系統的入口流量和系統的負載達到一個平衡,保證系統在能力范圍之內處理最多的請求

Sentinel 的開源生態:

Sentinel 分為兩個部分:

  • 核心庫(Java 客戶端)不依賴任何框架/庫,能夠運行於所有 Java 運行時環境,同時對 Dubbo / Spring Cloud 等框架也有較好的支持。
  • 控制台(Dashboard)基於 Spring Boot 開發,打包后可以直接運行,不需要額外的 Tomcat 等應用容器。

Sentinel 基本使用:

1.首先,我們需要導入依賴:

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>1.6.3</version>
</dependency>

2.定義資源限流規則:

  資源 是 Sentinel 中的核心概念之一。最常用的資源是我們代碼中的 Java 方法。 當然,您也可以更靈活的定義你的資源

//初始化規則
    private static void initFlowRules() {
        List<FlowRule> rules = new ArrayList<>(); //限流規則的集合
        FlowRule flowRule = new FlowRule();//限流規則
        flowRule.setResource("ruleTest");//資源(可以是方法名稱、接口)
        //線程數(FLOW_GRADE_THREAD)與QPS (FLOW_GRADE_QPS)
        flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS); //限流的閾值的類型
        flowRule.setCount(18);// QPS數
        rules.add(flowRule);
        FlowRuleManager.loadRules(rules);
    }

3.啟動測試類,官網提供了以下代碼做演示:

public static void main(String[] args) {
        initFlowRules(); //初始化一個規則
        while(true){
            Entry entry=null;
            try{
                entry= SphU.entry("ruleTest");
                System.out.println("Hello Word");
            }catch (BlockException e){//如果被限流了,那么會拋出這個異常
                e.printStackTrace();
            }finally {
                if(entry!=null){
                    entry.exit();// 釋放
                }
            }
        }
}

  Demo 運行之后,我們可以在日志 ~/logs/csp/${appName}-metrics.log.xxx 里看到下面的輸出:

  其中 p 代表通過的請求, block 代表被阻止的請求, s 代表成功執行完成的請求個數, e 代表用戶自定義的異常, rt 代表平均響應時長。可以看到,這個程序每秒穩定輸出 "hello world" 18 次,和規則中預先設定的閾值是一樣的。

Sentinel 控制台:

  下載 https://github.com/alibaba/Sentinel/releases ,下載 sentinel-dashboard-1.6.3.jar 。(啟動 Sentinel 控制台需要 JDK 版本為 1.8 及以上版本。)

  啟動控制台:

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

  其中 -Dserver.port=8080 用於指定 Sentinel 控制台端口為 8080。從 Sentinel 1.6.0 起,Sentinel 控制台引入基本的登錄功能,默認用戶名和密碼都是 sentinel

客戶端接入控制台:

  將剛剛演示的Demo 接入控制台,首秀按要導入依賴:

<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.6.3</version>
</dependency>

  啟動時加入 JVM 參數 -Dcsp.sentinel.dashboard.server=consoleIp:port 指定控制台地址和端口。若啟動多個應用,則需要通過 -Dcsp.sentinel.api.port=xxxx 指定客戶端監控 API 的端口(默認是 8719)。其他配置項見:https://github.com/alibaba/Sentinel/wiki/%E5%90%AF%E5%8A%A8%E9%85%8D%E7%BD%AE%E9%A1%B9 配置如下:

-Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-demo

  這樣子啟動Demo,客戶端配置好了與控制台的連接參數之后,並不會主動連接上控制台,需要觸發一次客戶端的規則才會開始進行初始化,並向控制台發送心跳和客戶端規則等信息。就能再控制台上看到效果如下:

  其他具體相關可以查看github介紹。

Sentinel 整合SpringBoot:

  Sentinel 提供了 @SentinelResource 注解用於定義資源,並提供了 AspectJ 的擴展用於自動定義資源、處理 BlockException 等。首先需要導入依賴:

<dependency>
  <groupId>com.alibaba.csp</groupId>
  <artifactId>sentinel-core</artifactId>
  <version>1.6.3</version>
</dependency>
<dependency>
  <groupId>com.alibaba.csp</groupId>
  <artifactId>sentinel-transport-simple-http</artifactId>
  <version>1.6.3</version>
</dependency>
<dependency>
  <groupId>com.alibaba.csp</groupId>
  <artifactId>sentinel-annotation-aspectj</artifactId>
  <version>1.6.3</version>
</dependency>

  在主啟動類中添加規則:

@SpringBootApplication
public class SentinelDemoApplication {

    public static void main(String[] args) {
        initFlowRules();
        SpringApplication.run(SentinelDemoApplication.class, args);
    }

    //初始化規則
    private static void initFlowRules(){
        List<FlowRule> rules=new ArrayList<>(); //限流規則的集合
        FlowRule flowRule=new FlowRule();
        flowRule.setResource("sayHello");//資源(方法名稱、接口)
        flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS); //限流的閾值的類型
        flowRule.setCount(2);
        rules.add(flowRule);
        FlowRuleManager.loadRules(rules);
    }

}

  還需要通過配置的方式將 SentinelResourceAspect 注冊為一個 Spring Bean:

@Configuration
public class AopConfiguration {

    @Bean
    public SentinelResourceAspect sentinelResourceAspect(){
        return new SentinelResourceAspect();
    }
}

  此刻我們可以通過注解 @SentinelResource 來定義資源 :

@RestController
public class SentinelController {
    
    //針對方法級別的限流
    @SentinelResource(value = "sayHello", blockHandler = "exceptionHandler", fallback = "fallbackHandler")
    @GetMapping("/say")
    public String sayHello(String name) {
        System.out.println("hello world");
        if (1 == 1) throw new RuntimeException("Hello");
        return "hello world";
    }

    // 該方法的參數除了 BlockException,包括參數、返回值,需要與原來的資源方法一致
    public String exceptionHandler(String name, BlockException ex) {
        return "blockHandler:" + name + ex.getMessage();
    }

    //用於在拋出異常的時候提供 fallback處理邏輯。
    public String fallbackHandler(String name) {
        return "fallbackHandler:" + name;
    }
}

  啟動服務就可以看到效果了。這里需要加入到Sentinel-dashboard中:-Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-demo


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM