隨著微服務(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ī)制如下:
對(duì)主流框架提供適配或者顯示的 API贮缅,來(lái)定義需要保護(hù)的資源榨咐,并提供設(shè)施對(duì)資源進(jìn)行實(shí)時(shí)統(tǒng)計(jì)和調(diào)用鏈路分析。
根據(jù)預(yù)設(shè)的規(guī)則谴供,結(jié)合對(duì)資源的實(shí)時(shí)統(tǒng)計(jì)信息块茁,對(duì)流量進(jìn)行控制。同時(shí)桂肌,Sentinel 提供開(kāi)放的接口数焊,方便您定義及改變規(guī)則。
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)自定義端口為8080
的Sentinel
控制臺(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函喉。
六、代碼實(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中就有了档叔。
七、 配置限流規(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>
- 資源名:唯一名稱(chēng)惦界,默認(rèn)請(qǐng)求路徑
- 針對(duì)來(lái)源:sentinel可以針對(duì)調(diào)用者進(jìn)行限流,填寫(xiě)微服務(wù)名稱(chēng)咙冗,默認(rèn)default表锻,表示不區(qū)分來(lái)源
- 閾值類(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)行限流瞬逊。 - 是否集群:不需要集群
- 流控模式:
直接:達(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)源旨巷。 - 流控效果:
快速失斁拊怠:直接失敗,拋異常采呐;
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 郭秀志
郊闯。 - 直接失敗
我們?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)
當(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ò)了閥值息尺。
我們?cè)賮?lái)請(qǐng)求/hello字币,發(fā)現(xiàn)被限流了。
這種關(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è)入口的流量了蝎毡。配置鏈路規(guī)則
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次吧。
這個(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ú)效蜕煌。
再次利用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):
- 平均響應(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ù)上面的判斷.
- 異常比例 (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%。
- 異常數(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!";
}
上面規(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)
在辆。九证薇、熱點(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ī)則配置:
這里配置的意思就是,
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才限流炬藤。配置如下圖:
當(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ī)則持久化參考如下文章。