Spring Cloud Alibaba(四校镐、流量防衛(wèi)組件Sentinel)

隨著微服務(wù)的流行,服務(wù)和服務(wù)之間的穩(wěn)定性變得越來(lái)越重要捺典。

一鸟廓、Sentinel 能干什么

Sentinel 是面向分布式服務(wù)架構(gòu)的輕量級(jí)流量控制產(chǎn)品,主要以流量為切入點(diǎn)襟己,從流量控制引谜、熔斷降級(jí)、系統(tǒng)負(fù)載保護(hù)等多個(gè)維度來(lái)幫助您保護(hù)服務(wù)的穩(wěn)定性擎浴。

二员咽、Sentinel 基本概念

2.1 資源

資源是 Sentinel 的關(guān)鍵概念。它可以是 Java 應(yīng)用程序中的任何內(nèi)容退客,例如骏融,由應(yīng)用程序提供的服務(wù),或由應(yīng)用程序調(diào)用的其它應(yīng)用提供的服務(wù)萌狂,甚至可以是一段代碼档玻。在接下來(lái)的文檔中,我們都會(huì)用資源來(lái)描述代碼塊茫藏。
只要通過(guò) Sentinel API 定義的代碼误趴,就是資源,能夠被 Sentinel 保護(hù)起來(lái)务傲。大部分情況下凉当,可以使用方法簽名,URL售葡,甚至服務(wù)名稱(chēng)作為資源名來(lái)標(biāo)示資源看杭。

2.2 規(guī)則

圍繞資源的實(shí)時(shí)狀態(tài)設(shè)定的規(guī)則,可以包括流量控制規(guī)則挟伙、熔斷降級(jí)規(guī)則以及系統(tǒng)保護(hù)規(guī)則楼雹。所有規(guī)則可以動(dòng)態(tài)實(shí)時(shí)調(diào)整。

三、Sentinel 是如何工作的

Sentinel 的主要工作機(jī)制如下:

  1. 對(duì)主流框架提供適配或者顯示的 API贮缅,來(lái)定義需要保護(hù)的資源榨咐,并提供設(shè)施對(duì)資源進(jìn)行實(shí)時(shí)統(tǒng)計(jì)和調(diào)用鏈路分析。

  2. 根據(jù)預(yù)設(shè)的規(guī)則谴供,結(jié)合對(duì)資源的實(shí)時(shí)統(tǒng)計(jì)信息块茁,對(duì)流量進(jìn)行控制。同時(shí)桂肌,Sentinel 提供開(kāi)放的接口数焊,方便您定義及改變規(guī)則。

  3. Sentinel 提供實(shí)時(shí)的監(jiān)控系統(tǒng)崎场,方便您快速了解目前系統(tǒng)的狀態(tài)昌跌。

四、Sentinel 功能和設(shè)計(jì)理念

4.1 流量控制

什么是流量控制
流量控制在網(wǎng)絡(luò)傳輸中是一個(gè)常用的概念照雁,它用于調(diào)整網(wǎng)絡(luò)包的發(fā)送數(shù)據(jù)。然而答恶,從系統(tǒng)穩(wěn)定性角度考慮饺蚊,在處理請(qǐng)求的速度上,也有非常多的講究悬嗓。任意時(shí)間到來(lái)的請(qǐng)求往往是隨機(jī)不可控的污呼,而系統(tǒng)的處理能力是有限的。我們需要根據(jù)系統(tǒng)的處理能力對(duì)流量進(jìn)行控制包竹。Sentinel 作為一個(gè)調(diào)配器燕酷,可以根據(jù)需要把隨機(jī)的請(qǐng)求調(diào)整成合適的形狀,如下圖所示:

流量控制
流量控制設(shè)計(jì)理念

流量控制有以下幾個(gè)角度:

  • 資源的調(diào)用關(guān)系周瞎,例如資源的調(diào)用鏈路苗缩,資源和資源之間的關(guān)系;
  • 運(yùn)行指標(biāo)声诸,例如 QPS酱讶、線(xiàn)程池、系統(tǒng)負(fù)載等彼乌;
  • 控制的效果泻肯,例如直接限流、冷啟動(dòng)慰照、排隊(duì)等灶挟。

Sentinel 的設(shè)計(jì)理念是讓您自由選擇控制的角度,并進(jìn)行靈活組合毒租,從而達(dá)到想要的效果稚铣。

4.2 熔斷降級(jí)

什么是熔斷降級(jí)

除了流量控制以外,降低調(diào)用鏈路中的不穩(wěn)定資源也是 Sentinel 的使命之一。由于調(diào)用關(guān)系的復(fù)雜性榛泛,如果調(diào)用鏈路中的某個(gè)資源出現(xiàn)了不穩(wěn)定蝌蹂,最終會(huì)導(dǎo)致請(qǐng)求發(fā)生堆積。這個(gè)問(wèn)題和 Hystrix 里面描述的問(wèn)題是一樣的曹锨。

Sentinel 和 Hystrix 的原則是一致的: 當(dāng)調(diào)用鏈路中某個(gè)資源出現(xiàn)不穩(wěn)定孤个,例如,表現(xiàn)為 timeout沛简,異常比例升高的時(shí)候齐鲤,則對(duì)這個(gè)資源的調(diào)用進(jìn)行限制,并讓請(qǐng)求快速失敗椒楣,避免影響到其它的資源给郊,最終產(chǎn)生雪崩的效果。

熔斷降級(jí)設(shè)計(jì)理念

在限制的手段上捧灰,Sentinel 和 Hystrix 采取了完全不一樣的方法淆九。

Hystrix 通過(guò)線(xiàn)程池的方式,來(lái)對(duì)依賴(lài)(在我們的概念中對(duì)應(yīng)資源)進(jìn)行了隔離毛俏。這樣做的好處是資源和資源之間做到了最徹底的隔離炭庙。缺點(diǎn)是除了增加了線(xiàn)程切換的成本,還需要預(yù)先給各個(gè)資源做線(xiàn)程池大小的分配煌寇。

Sentinel 對(duì)這個(gè)問(wèn)題采取了兩種手段:

  • 通過(guò)并發(fā)線(xiàn)程數(shù)進(jìn)行限制
    和資源池隔離的方法不同焕蹄,Sentinel 通過(guò)限制資源并發(fā)線(xiàn)程的數(shù)量,來(lái)減少不穩(wěn)定資源對(duì)其它資源的影響阀溶。這樣不但沒(méi)有線(xiàn)程切換的損耗腻脏,也不需要您預(yù)先分配線(xiàn)程池的大小。當(dāng)某個(gè)資源出現(xiàn)不穩(wěn)定的情況下银锻,例如響應(yīng)時(shí)間變長(zhǎng)永品,對(duì)資源的直接影響就是會(huì)造成線(xiàn)程數(shù)的逐步堆積。當(dāng)線(xiàn)程數(shù)在特定資源上堆積到一定的數(shù)量之后击纬,對(duì)該資源的新請(qǐng)求就會(huì)被拒絕腐碱。堆積的線(xiàn)程完成任務(wù)后才開(kāi)始繼續(xù)接收請(qǐng)求。

  • 通過(guò)響應(yīng)時(shí)間對(duì)資源進(jìn)行降級(jí)
    除了對(duì)并發(fā)線(xiàn)程數(shù)進(jìn)行控制以外掉弛,Sentinel 還可以通過(guò)響應(yīng)時(shí)間來(lái)快速降級(jí)不穩(wěn)定的資源症见。當(dāng)依賴(lài)的資源出現(xiàn)響應(yīng)時(shí)間過(guò)長(zhǎng)后,所有對(duì)該資源的訪(fǎng)問(wèn)都會(huì)被直接拒絕殃饿,直到過(guò)了指定的時(shí)間窗口之后才重新恢復(fù)谋作。

4.3 系統(tǒng)負(fù)載保護(hù)

Sentinel 同時(shí)對(duì)系統(tǒng)的維度提供保護(hù)。防止雪崩乎芳,是系統(tǒng)防護(hù)中重要的一環(huán)遵蚜。當(dāng)系統(tǒng)負(fù)載較高的時(shí)候帖池,如果還持續(xù)讓請(qǐng)求進(jìn)入,可能會(huì)導(dǎo)致系統(tǒng)崩潰吭净,無(wú)法響應(yīng)睡汹。在集群環(huán)境下,網(wǎng)絡(luò)負(fù)載均衡會(huì)把本應(yīng)這臺(tái)機(jī)器承載的流量轉(zhuǎn)發(fā)到其它的機(jī)器上去寂殉。如果這個(gè)時(shí)候其它的機(jī)器也處在一個(gè)邊緣狀態(tài)的時(shí)候囚巴,這個(gè)增加的流量就會(huì)導(dǎo)致這臺(tái)機(jī)器也崩潰,最后導(dǎo)致整個(gè)集群不可用友扰。

針對(duì)這個(gè)情況彤叉,Sentinel 提供了對(duì)應(yīng)的保護(hù)機(jī)制,讓系統(tǒng)的入口流量和系統(tǒng)的負(fù)載達(dá)到一個(gè)平衡村怪,保證系統(tǒng)在能力范圍之內(nèi)處理最多的請(qǐng)求秽浇。

五、啟動(dòng) Sentinel 控制臺(tái)

5.1 獲取 Sentinel 控制臺(tái)

支持直接下載和源碼構(gòu)建兩種方式:
1. 直接下載:下載 Sentinel 控制臺(tái)甚负,注:這個(gè)官方下載不能正常啟動(dòng)柬焕,并且版本較低。使用百度網(wǎng)盤(pán)下載梭域。
2. 源碼構(gòu)建:進(jìn)入 Sentinel Github 項(xiàng)目頁(yè)面击喂,將代碼 git clone 到本地自行編譯打包,參考此文檔碰辅。

5.2 啟動(dòng)控制臺(tái)

執(zhí)行 Java 命令 java -jar sentinel-dashboard.jar完成 Sentinel 控制臺(tái)的啟動(dòng)。 控制臺(tái)默認(rèn)的監(jiān)聽(tīng)端口為 8080介时。Sentinel 控制臺(tái)使用 Spring Boot 編程模型開(kāi)發(fā)没宾,如果需要指定其他端口,請(qǐng)使用 Spring Boot 容器配置的標(biāo)準(zhǔn)方式沸柔,詳情請(qǐng)參考 Spring Boot 文檔循衰。

寫(xiě)了一個(gè)批處理文件來(lái)啟動(dòng)自定義端口為8080Sentinel控制臺(tái),該文件內(nèi)容:
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -jar D:\backup\software\sentinel-dashboard-1.6.3.jar
-Dserver.port=8080 控制臺(tái)端口褐澎,sentinel控制臺(tái)是一個(gè)spring boot程序会钝。客戶(hù)端配置文件需要填對(duì)應(yīng)的配置工三。
-Dcsp.sentinel.dashboard.server=localhost:8080 控制臺(tái)的地址迁酸,指定控制臺(tái)后客戶(hù)端會(huì)自動(dòng)向該地址發(fā)送心跳包。
-Dproject.name=sentinel-dashboard 指定Sentinel控制臺(tái)程序的名稱(chēng)
-Dcsp.sentinel.api.port=8719 (默認(rèn)8719) 客戶(hù)端提供給Dashboard訪(fǎng)問(wèn)或者查看Sentinel的運(yùn)行訪(fǎng)問(wèn)的參數(shù)

注:

  • csp.sentinel.dashboard.server這個(gè)配置是用在客戶(hù)端俭正,這里Sentinel控制臺(tái)也使用是用于自己監(jiān)控自己程序的api奸鬓,否則無(wú)法顯示控制臺(tái)的api情況,當(dāng)然這個(gè)也可以根據(jù)情況不顯示掸读。
  • csp.sentinel.api.port=8719是客戶(hù)端的端口串远,需要把客戶(hù)端設(shè)置的端口穿透防火墻宏多,可在控制臺(tái)的“機(jī)器列表”中查看到端口號(hào),這里Sentinel控制臺(tái)也使用是用于自己程序的api傳輸澡罚,由于是默認(rèn)端口所以控制臺(tái)也可以不設(shè)置伸但。
  • 客戶(hù)端需向控制臺(tái)提供端口,配置文件配置留搔,如:spring.cloud.sentinel.transport.port=8720

從 Sentinel 1.6.0 起更胖,Sentinel 控制臺(tái)引入基本的登錄功能,默認(rèn)用戶(hù)名和密碼都是 sentinel催式。

5.3 訪(fǎng)問(wèn)控制臺(tái)

http://localhost:8080,默認(rèn)用戶(hù)名和密碼都是 sentinel函喉。

Sentinel控制臺(tái)首頁(yè)

六、代碼實(shí)踐

6.1 新建Module

6.1.1 POM文件,引入Sentinel starter荣月。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.pay.sentinel</groupId>
    <artifactId>sentinel</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sentinel</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
6.1.2 application.properties

增加配置管呵,在應(yīng)用的 /src/main/resources/application.properties 中添加基本配置信息。核心配置:spring.cloud.sentinel.transport.dashboard=localhost:8080哺窄。

#################################### common config : ####################################
spring.application.name=guoxiuzhi sentinel
# 應(yīng)用服務(wù)web訪(fǎng)問(wèn)端口
server.port=8090
# ActuatorWeb訪(fǎng)問(wèn)端口
management.server.port=8091
management.endpoints.jmx.exposure.include=*
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
# spring cloud access&secret config
# 可以訪(fǎng)問(wèn)如下地址查看: https://usercenter.console.aliyun.com/#/manage/ak
alibaba.cloud.access-key=****
alibaba.cloud.secret-key=****
#################################### sentinel config : ####################################
spring.cloud.sentinel.transport.dashboard=localhost:8080
management.health.sentinel.enabled=false
spring.cloud.sentinel.eager=true
6.1.3 SentinelApplication
package com.pay.sentinel.sentinel;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**   
 * @ClassName: SentinelApplication
 * @Description: 
 * @author: 郭秀志 jbcode@126.com
 * @date:   2020/6/15 9:35    
 * @Copyright:  
 */
@SpringBootApplication
public class SentinelApplication {

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

}
6.1.4 SentinelTestController
package com.pay.sentinel.sentinel.sentinel;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @ClassName: SentinelTestController
 * @Description: 測(cè)試Sentinel
 * @author: 郭秀志 jbcode@126.com
 * @date: 2020/6/15 9:20
 * @Copyright:
 */
@RestController
public class SentinelTestController {

    @GetMapping(value = "/hello")
    public String hello(@RequestParam String name) {
        return "Hello " + getName(name);
    }
    
    public String getName(String name) {
        return name;
    }

}

說(shuō)明:Sentinel starter 默認(rèn)為所有的 HTTP 服務(wù)提供了限流埋點(diǎn)捐下,如果只想對(duì) HTTP 服務(wù)進(jìn)行限流,那么只需要引入依賴(lài)萌业,無(wú)需修改代碼坷襟。

6.1.5 啟動(dòng)項(xiàng)目

訪(fǎng)問(wèn):http://localhost:8090/hello?name=郭秀志
如果Sentinel控制臺(tái)并沒(méi)有任何http://localhost:8090/test的相關(guān)信息,不要急生年,這是因?yàn)閟entinel使用懶加載機(jī)制婴程,沒(méi)調(diào)用的不會(huì)出現(xiàn)在dashboard中。訪(fǎng)問(wèn)一下抱婉,然后再看dashboard中就有了档叔。

Http服務(wù)自動(dòng)被埋點(diǎn)監(jiān)控

七、 配置限流規(guī)則

Sentinel 提供了兩種配置限流規(guī)則的方式:代碼配置 和 控制臺(tái)配置蒸绩。本示例使用的方式為通過(guò)控制臺(tái)配置衙四。

7.1 通過(guò)代碼來(lái)實(shí)現(xiàn)限流規(guī)則的配置。

一個(gè)簡(jiǎn)單的限流規(guī)則配置示例代碼如下患亿,更多限流規(guī)則配置詳情請(qǐng)參考 Sentinel 文檔传蹈。

List<FlowRule> rules = new ArrayList<FlowRule>();
FlowRule rule = new FlowRule();
rule.setResource(str);
// set limit qps to 10
rule.setCount(10);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp("default");
rules.add(rule);
FlowRuleManager.loadRules(rules);

7.2 通過(guò)控制臺(tái)進(jìn)行限流規(guī)則配置(我們采用這種方式

7.2.1 認(rèn)識(shí)規(guī)則
流控配置界面

在sentinel的dashboard中有一個(gè)流控規(guī)則,如上圖步藕,下面對(duì)這些名詞進(jìn)行解釋?zhuān)?/p>

  1. 資源名:唯一名稱(chēng)惦界,默認(rèn)請(qǐng)求路徑
  2. 針對(duì)來(lái)源:sentinel可以針對(duì)調(diào)用者進(jìn)行限流,填寫(xiě)微服務(wù)名稱(chēng)咙冗,默認(rèn)default表锻,表示不區(qū)分來(lái)源
  3. 閾值類(lèi)型:
    QPS(每秒鐘的請(qǐng)求數(shù)):當(dāng)調(diào)用該API的QPS達(dá)到閾值時(shí),進(jìn)行限流乞娄;
    線(xiàn)程數(shù):當(dāng)調(diào)用該API的線(xiàn)程數(shù)達(dá)到閾值時(shí)進(jìn)行限流瞬逊。
  4. 是否集群:不需要集群
  5. 流控模式:
    直接:達(dá)到限流條件時(shí)直接限流显歧;
    關(guān)聯(lián):關(guān)聯(lián)的資源達(dá)到閾值時(shí)限流自己(當(dāng)與A關(guān)聯(lián)的資源B達(dá)到閾值時(shí),就限流A自己确镊。應(yīng)用場(chǎng)景:支付服務(wù)達(dá)到閾值的時(shí)候士骤,就限流下訂單的服務(wù));
    鏈路:只記錄指定鏈路上的流量(指定資源從入口資源進(jìn)來(lái)的流量蕾域,如果達(dá)到閾值拷肌,就進(jìn)行限流,API級(jí)別的針對(duì)來(lái)源旨巷。
  6. 流控效果:
    快速失斁拊怠:直接失敗,拋異常采呐;
    warm up:根據(jù)codeFactor(冷加載因子若锁,默認(rèn)是3)的值,從閾值/codeFactor斧吐,經(jīng)過(guò)預(yù)熱時(shí)長(zhǎng)又固,才達(dá)到設(shè)置的QPS閾值;
    排隊(duì)等待:勻速排隊(duì)煤率,讓請(qǐng)求以勻速通過(guò)仰冠,閾值類(lèi)型必須設(shè)置為QPS,否則無(wú)效蝶糯。
7.2.2 配置實(shí)踐
  • 閾值類(lèi)型:QPS/流控模式:直接/流控效果:快速失敗
    流控配置界面

    設(shè)置的意思就是洋只,訪(fǎng)問(wèn)/hello,一秒鐘超過(guò)一次昼捍,就是直接快速報(bào)錯(cuò)识虚。我現(xiàn)在對(duì)http://localhost:8090/hello?name=郭秀志訪(fǎng)問(wèn)快速兩次,就會(huì)返回如下信息:Blocked by Sentinel (flow limiting)端三,代表被限流了。慢速訪(fǎng)問(wèn)鹃彻,正常返回:Hello 郭秀志郊闯。
  • 直接失敗
    線(xiàn)程數(shù)直接失敗

    我們?cè)僭L(fǎng)問(wèn)http://localhost:8090/hello?name=郭秀志,發(fā)現(xiàn)不管點(diǎn)多快蛛株,都沒(méi)有被流控給攔住团赁。因?yàn)槲覀冊(cè)谝粋€(gè)瀏覽器中訪(fǎng)問(wèn),始終是一個(gè)線(xiàn)程谨履。這樣配置的意思就是并發(fā)線(xiàn)程數(shù)超過(guò)閾值1時(shí)欢摄,就會(huì)返回失敗信息∷袼冢可以用jmeter模擬并發(fā)訪(fǎng)問(wèn)的情況怀挠。
  • 流控模式之關(guān)聯(lián)


    關(guān)聯(lián)

當(dāng)關(guān)聯(lián)的資源達(dá)到閥值析蝴,就限流自己。即關(guān)聯(lián)的資源是優(yōu)先保證的主資源绿淋。

意思就是/test的QPS數(shù)超過(guò)1闷畸,就會(huì)導(dǎo)致/hello不能用。測(cè)試方法:用jmeter對(duì)/test進(jìn)行并發(fā)訪(fǎng)問(wèn)吞滞,然后我們?cè)跒g覽器訪(fǎng)問(wèn)/hello佑菩。就會(huì)發(fā)現(xiàn)也會(huì)返回Blocked by Sentinel (flow limiting)
我們來(lái)驗(yàn)證一下裁赠,這里用了PostMan工具來(lái)調(diào)用/test,每隔200ms循環(huán)調(diào)用。這樣就保證關(guān)聯(lián)資源/test肯定超過(guò)了閥值息尺。

Postman循環(huán)調(diào)用 /test

我們?cè)賮?lái)請(qǐng)求/hello字币,發(fā)現(xiàn)被限流了。


/hello被動(dòng)限流

這種關(guān)聯(lián)模式有什么應(yīng)用場(chǎng)景呢失尖?
我們舉個(gè)例子啊奄,訂單服務(wù)中會(huì)有2個(gè)重要的接口,一個(gè)是讀取訂單信息接口掀潮,一個(gè)是寫(xiě)入訂單信息接口菇夸。
在高并發(fā)業(yè)務(wù)場(chǎng)景中,兩個(gè)接口都會(huì)占用資源仪吧,如果讀取接口訪(fǎng)問(wèn)過(guò)大庄新,就會(huì)影響寫(xiě)入接口的性能。業(yè)務(wù)中如果我們希望寫(xiě)入訂單比較重要薯鼠,要優(yōu)先考慮寫(xiě)入訂單接口择诈。那就可以利用關(guān)聯(lián)模式;
在資源名設(shè)置讀取接口出皇,關(guān)聯(lián)資源上面設(shè)置寫(xiě)入接口羞芍;這樣就起到了優(yōu)先寫(xiě)入,一旦寫(xiě)入請(qǐng)求多郊艘,就限制讀的請(qǐng)求荷科。

關(guān)聯(lián)模式的目標(biāo)就是保護(hù)關(guān)聯(lián)資源的。

  • 鏈路模式

只記錄鏈路入口的流量

上面是解釋?zhuān)悬c(diǎn)不是太清楚纱注,我們來(lái)看個(gè)案例畏浆,我們改造一下代碼。
增加了一個(gè)服務(wù)狞贱,方法用@SentinelResource進(jìn)行注解刻获,就是定義一個(gè)資源名。

package com.pay.sentinel.sentinel.sentinel;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.stereotype.Service;

/**
 * @ClassName: MyService
 * @Description:
 * @author: 郭秀志 jbcode@126.com
 * @date: 2020/6/15 16:58
 * @Copyright:
 */
@Service
public class MyService {
    @SentinelResource("chineseHello")
    public String getChineseHello() {
        return "你好";
    }
}

SentinelTestController使用Service

package com.pay.sentinel.sentinel.sentinel;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @ClassName: SentinelTestController
 * @Description: 測(cè)試Sentinel
 * @author: 郭秀志 jbcode@126.com
 * @date: 2020/6/15 9:20
 * @Copyright:
 */
@RestController
public class SentinelTestController {

    @Autowired
    MyService myService;

    @GetMapping(value = "/hello")
    @SentinelResource("helloResource")
    public String hello(@RequestParam String name) {
        String chineseHello = myService.getChineseHello();
        return chineseHello + "/Hello " + getName(name);
    }

    public String getName(String name) {
        return name;
    }

    @GetMapping(value = "/test")
    public String test() {
        String chineseHello = myService.getChineseHello();
        return chineseHello + "test!";
    }
}

讓/hello和/test都調(diào)用這個(gè)服務(wù)瞎嬉;那我們就可以利用鏈路模式設(shè)置限制哪個(gè)入口的流量了蝎毡。
“chineseHello” Sentinel Resource

配置鏈路規(guī)則


只針對(duì)url入口/test進(jìn)行限流
7.2.3 流控效果說(shuō)明

上面用的流控效果都是快速失敗厚柳,現(xiàn)在來(lái)認(rèn)識(shí)一下這些流控效果。

  • 快速失敹サ簟:上面的案例都是直接失敗草娜,就是超過(guò)閾值就返回Blocked by Sentinel (flow limiting)
  • 預(yù)熱( Warm Up):請(qǐng)求的QPS從 閾值 / 冷加載因子(默認(rèn)是3)開(kāi)始,經(jīng)過(guò) 預(yù)熱時(shí)長(zhǎng)痒筒,最后達(dá)到閾值宰闰。比如下圖的配置意思是:初始閾值為 10 / 3 = 3,經(jīng)過(guò)10秒鐘的時(shí)間簿透,閾值慢慢升到10∫婆郏現(xiàn)在快速訪(fǎng)問(wèn)testA,因?yàn)橐婚_(kāi)始QPS閾值為3老充,所以你點(diǎn)快一點(diǎn)可能就失敗了葡盗,但是慢慢地,你點(diǎn)很快都不會(huì)失敗了啡浊,因?yàn)樽詈箝撝瞪秊?0觅够,正常情況下沒(méi)有人手速能達(dá)到1秒鐘點(diǎn)11次吧。
預(yù)熱( Warm Up)

這個(gè)預(yù)熱的應(yīng)用場(chǎng)景巷嚣,如:秒殺系統(tǒng)在開(kāi)啟的瞬間喘先,會(huì)有很多流量上來(lái),很有可能把系統(tǒng)打死廷粒,預(yù)熱方式就是把為了保護(hù)系統(tǒng)窘拯,可慢慢的把流量放進(jìn)來(lái),慢慢的把閥值增長(zhǎng)到設(shè)置的閥值坝茎。

  • 排隊(duì)等待:就是不管同時(shí)有多少個(gè)請(qǐng)求過(guò)來(lái)涤姊,我每秒鐘只處理閾值數(shù)的請(qǐng)求,其他老老實(shí)實(shí)排隊(duì)等待去嗤放。如下圖配置意思就是每秒鐘只處理一個(gè)思喊,其他的排隊(duì)等著,每隔1000毫秒才放下一個(gè)請(qǐng)求進(jìn)來(lái)次酌。從字面上面就能夠猜到恨课,勻速排隊(duì),讓請(qǐng)求以均勻的速度通過(guò)和措,閥值類(lèi)型必須設(shè)成QPS庄呈,否則無(wú)效蜕煌。


    排隊(duì)等待

再次利用Postman工具派阱,循環(huán)請(qǐng)求/test,我們可以發(fā)現(xiàn)test的每隔1秒執(zhí)行一次斜纪,這么多的請(qǐng)求沒(méi)有被拒絕贫母,而且進(jìn)入的排隊(duì)文兑。
排隊(duì)的應(yīng)用場(chǎng)景是什么呢?
比如有時(shí)候系統(tǒng)在某一個(gè)時(shí)刻會(huì)出現(xiàn)大流量腺劣,之后流量就恢復(fù)穩(wěn)定绿贞,可以采用這種排隊(duì)模式,大流量來(lái)時(shí)可以讓流量請(qǐng)求先排隊(duì)橘原,等恢復(fù)了在慢慢進(jìn)行處理

八籍铁、熔斷降級(jí)

Sentinel除了流量控制以外,對(duì)調(diào)用鏈路中不穩(wěn)定的資源進(jìn)行熔斷降級(jí)也是保障高可用的重要措施之一趾断。由于調(diào)用關(guān)系的復(fù)雜性拒名,如果調(diào)用鏈路中的某個(gè)資源不穩(wěn)定,最終會(huì)導(dǎo)致請(qǐng)求發(fā)生堆積芋酌。Sentinel 熔斷降級(jí)會(huì)在調(diào)用鏈路中某個(gè)資源出現(xiàn)不穩(wěn)定狀態(tài)時(shí)(例如調(diào)用超時(shí)或異常比例升高)增显,對(duì)這個(gè)資源的調(diào)用進(jìn)行限制,讓請(qǐng)求快速失敗脐帝,避免影響到其它的資源而導(dǎo)致級(jí)聯(lián)錯(cuò)誤同云。當(dāng)資源被降級(jí)后,在接下來(lái)的降級(jí)時(shí)間窗口之內(nèi)堵腹,對(duì)該資源的調(diào)用都自動(dòng)熔斷(默認(rèn)行為是拋出 DegradeException)炸站。
Sentinel以三種方式衡量被訪(fǎng)問(wèn)的資源是否處理穩(wěn)定的狀態(tài):

  1. 平均響應(yīng)時(shí)間 (DEGRADE_GRADE_RT):當(dāng)資源的平均響應(yīng)時(shí)間超過(guò)閾值(DegradeRule 中的 count,以 ms 為單位)之后秸滴,資源進(jìn)入準(zhǔn)降級(jí)狀態(tài)武契。接下來(lái)如果持續(xù)進(jìn)入 5 個(gè)請(qǐng)求,它們的 RT 都持續(xù)超過(guò)這個(gè)閾值荡含,那么在接下的時(shí)間窗口(DegradeRule 中的 timeWindow咒唆,以 s 為單位)之內(nèi),對(duì)這個(gè)方法的調(diào)用都會(huì)自動(dòng)地返回(拋出 DegradeException)释液。在下一個(gè)時(shí)間窗口到來(lái)時(shí), 會(huì)接著再放入5個(gè)請(qǐng)求, 再重復(fù)上面的判斷.
  2. 異常比例 (DEGRADE_GRADE_EXCEPTION_RATIO):當(dāng)資源的每秒異橙停總數(shù)占通過(guò)量的比值超過(guò)閾值(DegradeRule 中的 count)之后,資源進(jìn)入降級(jí)狀態(tài)误债,即在接下的時(shí)間窗口(DegradeRule中的 timeWindow浸船,以 s 為單位)之內(nèi),對(duì)這個(gè)方法的調(diào)用都會(huì)自動(dòng)地返回寝蹈。異常比率的閾值范圍是 [0.0, 1.0]李命,代表 0% - 100%。
  3. 異常數(shù) (DEGRADE_GRADE_EXCEPTION_COUNT):當(dāng)資源近 1 分鐘的異常數(shù)目超過(guò)閾值之后會(huì)進(jìn)行熔斷箫老。
    修改Controller封字,增加sleep時(shí)間,使其滿(mǎn)足降級(jí)條件。
    @GetMapping(value = "/test")
    public String test() {
        String chineseHello = myService.getChineseHello();
        try {
            Thread.sleep(1500);//sleep 1.5秒返回結(jié)果
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("chineseHello = " + chineseHello);
        return chineseHello + "test!";
    }

降級(jí)配置參考圖

上面規(guī)則的含義:當(dāng)資源的平均響應(yīng)時(shí)間超過(guò)閾值500(以 ms 為單位)之后阔籽,資源進(jìn)入準(zhǔn)降級(jí)狀態(tài)流妻。接下來(lái)如果持續(xù)進(jìn)入 5 個(gè)請(qǐng)求,它們的 RT 都持續(xù)超過(guò)這個(gè)閾值笆制,那么在接下的時(shí)間窗口10(以 s 為單位)之內(nèi)绅这,對(duì)這個(gè)方法的調(diào)用都會(huì)自動(dòng)地返回(拋出 DegradeException),實(shí)測(cè)是返回Blocked by Sentinel (flow limiting)在辆。
熔斷降級(jí)返回內(nèi)容

九证薇、熱點(diǎn)規(guī)則

9.1 熱點(diǎn)規(guī)則是什么?

就是針對(duì)熱點(diǎn)數(shù)據(jù)做限流匆篓。比如id為1的商品是熱點(diǎn)數(shù)據(jù)棕叫,那么可以針對(duì)id為1的這個(gè)商品做限流。

9.2 Controller中加一個(gè)方法奕删,如下:

@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey", blockHandler = "deal_testHotKey") // 這個(gè)value值隨意俺泣,只要唯一即可,但是一般和@GetMapping中的一致
public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
                         @RequestParam(value = "p2", required = false) String p2) {
        return "test hot key";
}

/**
* 兜底方法完残,參數(shù)除了原方法的參數(shù)伏钠,還要加上BlockException
* @param p1
* @param p2
* @param e
* @return
*/
public String deal_testHotKey(String p1, String p2, BlockException e) {
    return "兜底方法";
}

9.3 熱點(diǎn)規(guī)則配置:

熱點(diǎn)規(guī)則

這里配置的意思就是,testHotKey(就是@SentinelResource中的value值)這個(gè)資源谨设,我對(duì)索引為0的參數(shù)(p1)進(jìn)行監(jiān)控熟掂,如果訪(fǎng)問(wèn)testHotKey帶上了p1,并且QPS超過(guò)了1扎拣,那么接下來(lái)的1秒中內(nèi)這個(gè)方法都會(huì)被降級(jí)赴肚。注意:索引為0的參數(shù)是p1,是controller中接收參數(shù)的順序的索引二蓝。你訪(fǎng)問(wèn)http://192.168.0.104:8090/testHotKey?p2=1誉券,這里只有一個(gè)參數(shù)p2,在url中它是第0個(gè)參數(shù)刊愚,但是在controller中不是踊跟,所以這樣訪(fǎng)問(wèn)并不會(huì)被降級(jí)。

9.3.1 熱點(diǎn)配置的高級(jí)選項(xiàng)

參數(shù)例外項(xiàng):上面的配置對(duì)p1進(jìn)行限流鸥诽,不管p1的值是多少商玫,只要QPS超過(guò)1,就降級(jí)∧到瑁現(xiàn)在的需求是如果p1的值是5拳昌,我就搞特殊的,因?yàn)樗荲IP钠龙,所以讓它QPS超過(guò)100才限流炬藤。配置如下圖:


參數(shù)例外項(xiàng)

當(dāng)參數(shù)不是5時(shí)扁远,QPS超過(guò)1就會(huì)被限流降級(jí),p1的值為5時(shí)刻像,你狂點(diǎn)都可以正常訪(fǎng)問(wèn)。
注意:@SentinelResource只管我們控制臺(tái)配置的違規(guī)情況并闲,才會(huì)進(jìn)行兜底细睡,假如程序異常了,它是管不了的帝火。比如我們?cè)趓eturn 前加一行int a = 10 / 0溜徙,它還是會(huì)返回error page的,而不是兜底方法犀填。

9.4 測(cè)試

訪(fǎng)問(wèn):http://localhost:8090/testHotKey?p1=guo&p2=xiuzhi
正常返回:test hot key
如果訪(fǎng)問(wèn)過(guò)快蠢壹,返回:兜底方法

訪(fǎng)問(wèn):http://localhost:8090/testHotKey?p1=5&p2=xiuzhi
正常返回:test hot key
如果訪(fǎng)問(wèn)過(guò)快,同樣返回:test hot key

十九巡、規(guī)則丟失

無(wú)論是通過(guò)硬編碼的方式來(lái)更新規(guī)則图贸,還是通過(guò)接入 Sentinel Dashboard 后,在頁(yè)面上操作來(lái)更新規(guī)則冕广,都無(wú)法避免一個(gè)問(wèn)題疏日,那就是服務(wù)重新后,規(guī)則就丟失了撒汉,因?yàn)槟J(rèn)情況下規(guī)則是保存在內(nèi)存中的沟优。規(guī)則持久化參考如下文章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末睬辐,一起剝皮案震驚了整個(gè)濱河市挠阁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌溯饵,老刑警劉巖侵俗,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異丰刊,居然都是意外死亡坡慌,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)藻三,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)洪橘,“玉大人,你說(shuō)我怎么就攤上這事棵帽∠ㄇ螅” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵逗概,是天一觀的道長(zhǎng)弟晚。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么卿城? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任枚钓,我火速辦了婚禮,結(jié)果婚禮上瑟押,老公的妹妹穿的比我還像新娘搀捷。我一直安慰自己,他們只是感情好多望,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布嫩舟。 她就那樣靜靜地躺著,像睡著了一般怀偷。 火紅的嫁衣襯著肌膚如雪家厌。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,764評(píng)論 1 290
  • 那天椎工,我揣著相機(jī)與錄音饭于,去河邊找鬼。 笑死维蒙,一個(gè)胖子當(dāng)著我的面吹牛镰绎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播木西,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼畴栖,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了八千?” 一聲冷哼從身側(cè)響起吗讶,我...
    開(kāi)封第一講書(shū)人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎恋捆,沒(méi)想到半個(gè)月后照皆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡沸停,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年膜毁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片愤钾。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瘟滨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出能颁,到底是詐尸還是另有隱情杂瘸,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布伙菊,位于F島的核電站败玉,受9級(jí)特大地震影響敌土,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜运翼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一返干、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧血淌,春花似錦矩欠、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)峰伙。三九已至疗疟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間瞳氓,已是汗流浹背策彤。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留匣摘,地道東北人店诗。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像音榜,于是被迫代替她去往敵國(guó)和親庞瘸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348