副本介紹
分布式系統(tǒng)中,我們往往會(huì)遇到一些服務(wù)可用性問(wèn)題?出現(xiàn)這些問(wèn)題的原因是什么?我們又應(yīng)該如何解決這些問(wèn)題呢?
第一關(guān):分布式系統(tǒng)中遇到的問(wèn)題
服務(wù)的可用性問(wèn)題
4個(gè)9 5個(gè)9 x個(gè)9。
x代表了3-5。 代表系統(tǒng)一年使用過(guò)程中,系統(tǒng)可以正常使用時(shí)間與總時(shí)間(1年)之比。
例如 4個(gè)9. (1-99.99%)x365x24=0.876小時(shí)=52.6分鐘,表示該系統(tǒng)在連續(xù)運(yùn)行1年時(shí)間里最多可能的業(yè)務(wù)中斷時(shí)間是52.6分鐘。

服務(wù)雪崩效應(yīng): 因服務(wù)提供者的不可用導(dǎo)致服務(wù)調(diào)用者的不可用,并將不可用逐漸放大的過(guò)程,就叫服務(wù)雪崩效應(yīng)。
導(dǎo)致服務(wù)不可用的原因:

Reliability && Resilience
常見(jiàn)的容錯(cuò)機(jī)制:
-
超時(shí)機(jī)制
在不做任何處理的情況下,服務(wù)提供者不可用會(huì)導(dǎo)致消費(fèi)者請(qǐng)求線程強(qiáng)制等待,而造成系統(tǒng)資源耗盡。加入超時(shí)機(jī)制,一旦超時(shí),就釋放資源。由于釋放資源速度較快,一定程度上可以抑制資源耗盡的問(wèn)題。
-
服務(wù)限流
服務(wù)限流 -
隔離
用戶的請(qǐng)求將不再直接訪問(wèn)服務(wù),而是通過(guò)線程池中的空閑線程來(lái)訪問(wèn)服務(wù),如果線程池已滿,則會(huì)進(jìn)行降級(jí)處理,用戶的請(qǐng)求不會(huì)被阻塞,至少可以看到一個(gè)執(zhí)行結(jié)果(例如返回友好的提示信息),而不是無(wú)休止的等待或者看到系統(tǒng)崩潰。
第二關(guān):Sentinel 介紹
Sentinel 是什么?
Sentinel 是阿里開(kāi)源的,面向分布式服務(wù)架構(gòu)的高可用防護(hù)組件。提供了多維度的流控降級(jí)能力,秒級(jí)實(shí)時(shí)監(jiān)控與動(dòng)態(tài)規(guī)則管理。主要以流量為切入點(diǎn),從限流、流量整形、熔斷降級(jí)、系統(tǒng)負(fù)載保護(hù)、熱點(diǎn)防護(hù)等多個(gè)維度來(lái)幫助開(kāi)發(fā)者保障微服務(wù)的穩(wěn)定性。
Sentinel 具有以下特征:
- 豐富的應(yīng)用場(chǎng)景: Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場(chǎng)景,例如秒殺(即突發(fā)流量控制在系統(tǒng)容量可以承受的范圍)、消息削峰填谷、實(shí)時(shí)熔斷下游不可用應(yīng)用等。
- 完備的實(shí)時(shí)監(jiān)控: Sentinel 同時(shí)提供實(shí)時(shí)的監(jiān)控功能。您可以在控制臺(tái)中看到接入應(yīng)用的單臺(tái)機(jī)器秒級(jí)數(shù)據(jù),甚至 500 臺(tái)以下規(guī)模的集群的匯總運(yùn)行情況。
- 廣泛的開(kāi)源生態(tài): Sentinel 提供開(kāi)箱即用的與其它開(kāi)源框架/庫(kù)的整合模塊,例如與 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相應(yīng)的依賴并進(jìn)行簡(jiǎn)單的配置即可快速地接入 Sentinel。
- 完善的 SPI 擴(kuò)展點(diǎn): Sentinel 提供簡(jiǎn)單易用、完善的 SPI 擴(kuò)展點(diǎn)。您可以通過(guò)實(shí)現(xiàn)擴(kuò)展點(diǎn),快速的定制邏輯。例如定制規(guī)則管理、適配數(shù)據(jù)源等。
Sentinel 分為兩部分:
- 核心庫(kù)(Java 客戶端)不依賴任何框架/庫(kù),能夠運(yùn)行于所有 Java 運(yùn)行時(shí)環(huán)境,同時(shí)對(duì) Dubbo / Spring Cloud 等框架也有較好的支持。
- 控制臺(tái)(Dashboard)基于 Spring Boot 開(kāi)發(fā),打包后可以直接運(yùn)行,不需要額外的 Tomcat 等應(yīng)用容器。
Sentinel 和 Hystrix對(duì)比

第三關(guān):Sentinel - 實(shí)踐<原生Spring>
1. 補(bǔ)充pom文件
<!--sentinel核心庫(kù)-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.0</version>
</dependency>
<!--如果要使用@SentinelResource-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.8.0</version>
</dependency>
<!--整合控制臺(tái)-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.0</version>
</dependency>
2. 啟動(dòng)類中配置bean - SentinelResourceAspect
如果是通過(guò) SpringCloud Alibaba 接入的 Sentinel,則無(wú)需進(jìn)行額外配置,就可以使用 @SentinelResource 注解
若使用的是Spring AOP ( 無(wú)論是 SpringBoot 還是 傳統(tǒng)的 Spring 應(yīng)用 ),則需要配置下面的bean
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
3. 自定義降級(jí)控流、熔斷的方法
/**
* 定義規(guī)則
*
* spring 的初始化方法
*/
@PostConstruct //該注解的接口會(huì)在spring啟動(dòng)的時(shí)候,自動(dòng)執(zhí)行
private static void initFlowRules(){
// 流控規(guī)則
List<FlowRule> rules = new ArrayList<>();
// 流控
FlowRule rule = new FlowRule();
// 為哪個(gè)資源進(jìn)行流控
rule.setResource(RESOURCE_NAME); //資源名同接口地址
// 設(shè)置流控規(guī)則 QPS
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 設(shè)置受保護(hù)的資源閾值
// Set limit QPS to 20.
rule.setCount(1);
rules.add(rule);
// 通過(guò)@SentinelResource來(lái)定義資源并配置降級(jí)和流控的處理方法
FlowRule rule2 = new FlowRule();
//設(shè)置受保護(hù)的資源
rule2.setResource(USER_RESOURCE_NAME);
// 設(shè)置流控規(guī)則 QPS
rule2.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 設(shè)置受保護(hù)的資源閾值
// Set limit QPS to 20.
rule2.setCount(1);
rules.add(rule2);
// 加載配置好的規(guī)則
FlowRuleManager.loadRules(rules);
}
@PostConstruct // 初始化
public void initDegradeRule(){
/*降級(jí)規(guī)則 異常*/
List<DegradeRule> degradeRules = new ArrayList<>();
DegradeRule degradeRule = new DegradeRule();
degradeRule.setResource(DEGRADE_RESOURCE_NAME);
// 設(shè)置規(guī)則策略: 異常數(shù)
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
// 觸發(fā)熔斷異常數(shù) : 2
degradeRule.setCount(2);
// 觸發(fā)熔斷最小請(qǐng)求數(shù):2
degradeRule.setMinRequestAmount(2);
// 統(tǒng)計(jì)時(shí)長(zhǎng): 單位:ms 1分鐘
degradeRule.setStatIntervalMs(60*1000); // 時(shí)間太短不好測(cè)
// 一分鐘內(nèi): 執(zhí)行了2次以上 出現(xiàn)了2次異常 就會(huì)觸發(fā)熔斷
// 熔斷持續(xù)時(shí)長(zhǎng) : 單位 秒
// 一旦觸發(fā)了熔斷, 再次請(qǐng)求對(duì)應(yīng)的接口就會(huì)直接調(diào)用 降級(jí)方法。
// 10秒過(guò)了后——半開(kāi)狀態(tài): 恢復(fù)接口請(qǐng)求調(diào)用, 如果第一次請(qǐng)求就異常, 再次熔斷,不會(huì)根據(jù)設(shè)置的條件進(jìn)行判定
degradeRule.setTimeWindow(10);
degradeRules.add(degradeRule);
DegradeRuleManager.loadRules(degradeRules);
/*
慢調(diào)用比率--DEGRADE_GRADE_RT
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
degradeRule.setCount(100);
degradeRule.setTimeWindow(10);
//請(qǐng)求總數(shù)小于minRequestAmount時(shí)不做熔斷處理
degradeRule.setMinRequestAmount(2);
// 在這個(gè)時(shí)間段內(nèi)2次請(qǐng)求
degradeRule.setStatIntervalMs(60*1000*60); // 時(shí)間太短不好測(cè)
// 慢請(qǐng)求率:慢請(qǐng)求數(shù)/總請(qǐng)求數(shù)> SlowRatioThreshold ,
// 這里要設(shè)置小于1 因?yàn)槁?qǐng)求數(shù)/總請(qǐng)求數(shù) 永遠(yuǎn)不會(huì)大于1
degradeRule.setSlowRatioThreshold(0.9);*/
}
4. 給對(duì)應(yīng)接口添加 @SentinelResource 注解
private static final String USER_RESOURCE_NAME = "user";
/**
* @SentinelResource 改善接口中資源定義和被流控降級(jí)后的處理方法
* 怎么使用: 1.添加依賴<artifactId>sentinel-annotation-aspectj</artifactId>
* 2.配置bean——SentinelResourceAspect
* value 定義資源
* blockHandler 設(shè)置 流控降級(jí)后的處理方法(默認(rèn)該方法必須聲明在同一個(gè)類)
* 如果不想在同一個(gè)類中 添加blockHandlerClass指定對(duì)應(yīng)的類 但是方法必須是static
* fallback 當(dāng)接口出現(xiàn)了異常,就可以交給fallback指定的方法進(jìn)行處理
* 如果不想在同一個(gè)類中 添加fallbackClass指定對(duì)應(yīng)的類 但是方法必須是static
* blockHandler 如果和fallback同時(shí)指定了,則blockHandler優(yōu)先級(jí)更高
*
* exceptionsToIgnore 排除哪些異常不處理
* @param id
* @return
*/
@RequestMapping("/user")
@SentinelResource(value = USER_RESOURCE_NAME, fallback = "fallbackHandleForGetUser",
/*exceptionsToIgnore = {ArithmeticException.class},*/
/*blockHandlerClass = User.class,*/ blockHandler = "blockHandlerForGetUser")
public User getUser(String id) {
int a=1/0;
return new User("成功");
}
public User fallbackHandleForGetUser(String id,Throwable e) {
e.printStackTrace();
return new User("異常處理");
}
/**
* 注意:
* 1. 一定要public
* 2. 返回值一定要和源方法保證一致, 包含源方法的參數(shù)。
* 3. 可以在參數(shù)最后添加BlockException 可以區(qū)分是什么規(guī)則的處理方法
* @param id
* @param ex
* @return
*/
public User blockHandlerForGetUser(String id, BlockException ex) {
ex.printStackTrace();
return new User("流控!!");
}
第四關(guān):Sentinel - 整合SpringCloud Alibaba
-
補(bǔ)充pom文件
<!--sentinel啟動(dòng)器--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> -
補(bǔ)充配置文件
這樣我們請(qǐng)求了該服務(wù)的接口后,sentinel控制臺(tái)就會(huì)有記錄了
server: port: 8861 spring: application: name: order-sentinel cloud: sentinel: transport: dashboard: 192.168.2.101:8858 web-context-unify: false # 默認(rèn)將調(diào)用鏈路收斂, 導(dǎo)致鏈路流控效果無(wú)效
請(qǐng)求接口被流控就會(huì)被sentinel默認(rèn)的方法展示。想要自定義流控方法的返回,跟Sentinel整合原生Spring 一樣, 通過(guò)加注解@SentinelResource(value = "xx", blockHandler = "流控方法名"),自定義流控方法來(lái)實(shí)現(xiàn)。
除此之外,當(dāng)我們多個(gè)方法的流控、降級(jí)、熔斷方法返回值都一樣,就可以編寫(xiě)自定義攔截器進(jìn)行統(tǒng)一處理
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tulingxueyuan.order.domain.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {
Logger log = LoggerFactory.getLogger(this.getClass());
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse response, BlockException e) throws Exception {
// getRule() 資源 規(guī)則的詳細(xì)信息
log.info("BlockExceptionHandler BlockException================"+e.getRule());
Result r = null;
if (e instanceof FlowException) {
r = Result.error(100,"接口限流了");
} else if (e instanceof DegradeException) {
r = Result.error(101,"服務(wù)降級(jí)了");
} else if (e instanceof ParamFlowException) {
r = Result.error(102,"熱點(diǎn)參數(shù)限流了");
} else if (e instanceof SystemBlockException) {
r = Result.error(103,"觸發(fā)系統(tǒng)保護(hù)規(guī)則了");
} else if (e instanceof AuthorityException) {
r = Result.error(104,"授權(quán)規(guī)則不通過(guò)");
}
//返回json數(shù)據(jù)
response.setStatus(500);
response.setCharacterEncoding("utf-8");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
new ObjectMapper().writeValue(response.getWriter(), r);
}
}
第五關(guān):Sentinel-Dashboard 安裝
Sentinel 控制臺(tái): https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0
docker安裝控制臺(tái)
搜索、下載容器
[root@192 ~]# docker search sentinel
[root@192 ~]# docker pull bladex/sentinel-dashboard
啟動(dòng)容器
docker run --name sentinel-dashboard -d -p 8858:8858 bladex/sentinel-dashboard
客戶端接入控制臺(tái)
引入pom文件
客戶端需要引入 Transport 模塊來(lái)與 Sentinel 控制臺(tái)進(jìn)行通信。您可以通過(guò) `pom.xml` 引入 JAR 包
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>x.y.z</version>
</dependency>
配置啟動(dòng)參數(shù) ( 原生spring )
啟動(dòng)時(shí)加入 JVM 參數(shù) `-Dcsp.sentinel.dashboard.server=192.168.2.101:8858` 指定控制臺(tái)地址和端口。若啟動(dòng)多個(gè)應(yīng)用,則需要通過(guò) `-Dcsp.sentinel.api.port=xxxx` 指定客戶端監(jiān)控 API 的端口(默認(rèn)是 8719)。
從 1.6.3 版本開(kāi)始,控制臺(tái)支持網(wǎng)關(guān)流控規(guī)則管理。您需要在接入端添加 `-Dcsp.sentinel.app.type=1` 啟動(dòng)參數(shù)以將您的服務(wù)標(biāo)記為 API Gateway,在接入控制臺(tái)時(shí)您的服務(wù)會(huì)自動(dòng)注冊(cè)為網(wǎng)關(guān)類型,然后您即可在控制臺(tái)配置網(wǎng)關(guān)規(guī)則和 API 分組。
除了修改 JVM 參數(shù),也可以通過(guò)配置文件取得同樣的效果。更詳細(xì)的信息可以參考 啟動(dòng)配置項(xiàng)。
第六關(guān):流控規(guī)則 < 流控通常在服務(wù)端 >
流控模式
直接流控 關(guān)聯(lián)流控 鏈路流控
1、直接流控
給誰(shuí)設(shè)置流控,達(dá)到要求,誰(shuí)就被限流。
2、關(guān)聯(lián)流控
給接口A設(shè)置流控,關(guān)聯(lián)資源是接口B。 這時(shí)候,當(dāng)請(qǐng)求B達(dá)到一定要求,A就會(huì)被限流。
3、鏈路流控
接口A和接口B都調(diào)用了接口C。我們對(duì)C設(shè)置鏈路流控,入口資源是接口A。這時(shí)候,當(dāng)接口A調(diào)用達(dá)到一定要求,接口A請(qǐng)求C就被流控了。但是接口B請(qǐng)求C不管怎么請(qǐng)求,都是可以調(diào)通的。
// 接口C
@SentinelResource(value="getUser",blockHandler = "blockHandlerGetUser")
public String getUser() {
return "查詢用戶";
}
// 關(guān)聯(lián)流控 訪問(wèn) 觸發(fā)/getUser
@RequestMapping("/test1")
public String test1(){
return orderService.getUser();
}
// 關(guān)聯(lián)流控 訪問(wèn)/add 觸發(fā)/get
@RequestMapping("/test2")
public String test2() throws InterruptedException {
return orderService.getUser();
}

測(cè)試會(huì)發(fā)現(xiàn)鏈路規(guī)則不生效
注意,高版本此功能直接使用不生效,如何解決?
從1.6.3 版本開(kāi)始,Sentinel Web filter默認(rèn)收斂所有URL的入口context,因此鏈路限流不生效。
1.7.0 版本開(kāi)始(對(duì)應(yīng)SCA的2.1.1.RELEASE),官方在CommonFilter 引入了WEB_CONTEXT_UNIFY 參數(shù),用于控制是否收斂context。將其配置為 false 即可根據(jù)不同的URL 進(jìn)行鏈路限流。SCA 2.1.1.RELEASE之后的版本,可以通過(guò)配置spring.cloud.sentinel.web-context-unify=false即可關(guān)閉收斂
server:
port: 8861
spring:
application:
name: order-sentinel
cloud:
sentinel:
transport:
dashboard: 192.168.2.101:8858
web-context-unify: false # 默認(rèn)將調(diào)用鏈路收斂, 導(dǎo)致鏈路流控效果無(wú)效
流控效果
快速失敗 Warm Up 排隊(duì)等待
1、快速失敗
超出要求,直接失敗,走流控方法 ( block )
官方解釋: ( RuleConstant.CONTROL_BEHAVIOR_DEFAULT )方式是默認(rèn)的流量控制方式,當(dāng)QPS超過(guò)任意規(guī)則的閾值后,新的請(qǐng)求就會(huì)被立即拒絕,拒絕方式為拋出FlowException。這種方式適用于對(duì)系統(tǒng)處理能力確切已知的情況下,比如通過(guò)壓測(cè)確定了系統(tǒng)的準(zhǔn)確水位時(shí)。
2、Warm Up
適用于 洪峰流量 ,預(yù)熱模式,一點(diǎn)一點(diǎn)給釋放
官方解釋: Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即預(yù)熱/冷啟動(dòng)方式。當(dāng)系統(tǒng)長(zhǎng)期處于低水位的情況下,當(dāng)流量突然增加時(shí),直接把系統(tǒng)拉升到高水位可能瞬間把系統(tǒng)壓垮。通過(guò)"冷啟動(dòng)",讓通過(guò)的流量緩慢增加,在一定時(shí)間內(nèi)逐漸增加到閾值上限,給冷系統(tǒng)一個(gè)預(yù)熱的時(shí)間,避免冷系統(tǒng)被壓垮。
冷加載因子: codeFactor 默認(rèn)是3,即請(qǐng)求 QPS 從 threshold / 3 開(kāi)始,經(jīng)預(yù)熱時(shí)長(zhǎng)逐漸升至設(shè)定的 QPS 閾值。
3、排隊(duì)等待
適用于 脈沖流量 ,雪峰填谷的意思
官方解釋: 勻速排隊(duì)(
RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式會(huì)嚴(yán)格控制請(qǐng)求通過(guò)的間隔時(shí)間,也即是讓請(qǐng)求以均勻的速度通過(guò),對(duì)應(yīng)的是漏桶算法。這種方式主要用于處理間隔性突發(fā)的流量,例如消息隊(duì)列。想象一下這樣的場(chǎng)景,在某一秒有大量的請(qǐng)求到來(lái),而接下來(lái)的幾秒則處于空閑狀態(tài),我們希望系統(tǒng)能夠在接下來(lái)的空閑期間逐漸處理這些請(qǐng)求,而不是在第一秒直接拒絕多余的請(qǐng)求。注意: 勻速排隊(duì)模式暫時(shí)不支QPS > 1000 的請(qǐng)求
第七關(guān):熔斷降級(jí)與隔離 < 通常在消費(fèi)端 >
降級(jí)規(guī)則
除了流量控制以外,對(duì)調(diào)用鏈路中不穩(wěn)定的資源進(jìn)行熔斷降級(jí)也是保障高可用的重要措施之一。我們需要對(duì)不穩(wěn)定的 **弱依賴服務(wù)調(diào)用** 進(jìn)行熔斷降級(jí),暫時(shí)切斷不穩(wěn)定調(diào)用,避免局部不穩(wěn)定因素導(dǎo)致整體的雪崩。熔斷降級(jí)作為保護(hù)自身的手段,通常在客戶端(調(diào)用端)進(jìn)行配置。
熔斷策略
慢調(diào)用比例
設(shè)置最大響應(yīng)時(shí)間,超過(guò)了就是慢調(diào)用。 超過(guò)慢調(diào)用比例就會(huì)被熔斷降級(jí)。熔斷之后第一次調(diào)用如果還是慢調(diào)用,則直接再次熔斷,不必判斷慢調(diào)用比例。
官方解釋: 慢調(diào)用比例 (SLOW_REQUEST_RATIO):選擇以慢調(diào)用比例作為閾值,需要設(shè)置允許的慢調(diào)用 RT(即最大的響應(yīng)時(shí)間),請(qǐng)求的響應(yīng)時(shí)間大于該值則統(tǒng)計(jì)為慢調(diào)用。當(dāng)單位統(tǒng)計(jì)時(shí)長(zhǎng)(statIntervalMs)內(nèi)請(qǐng)求數(shù)目大于設(shè)置的最小請(qǐng)求數(shù)目,并且慢調(diào)用的比例大于閾值,則接下來(lái)的熔斷時(shí)長(zhǎng)內(nèi)請(qǐng)求會(huì)自動(dòng)被熔斷。經(jīng)過(guò)熔斷時(shí)長(zhǎng)后熔斷器會(huì)進(jìn)入探測(cè)恢復(fù)狀態(tài)(HALF-OPEN 狀態(tài)),若接下來(lái)的一個(gè)請(qǐng)求響應(yīng)時(shí)間小于設(shè)置的慢調(diào)用 RT 則結(jié)束熔斷,若大于設(shè)置的慢調(diào)用 RT 則會(huì)再次被熔斷。

異常比例
在設(shè)定的**最小請(qǐng)求**的基礎(chǔ)上,出現(xiàn)異常的概率**大于異常比例**,之后的請(qǐng)求則會(huì)熔斷降級(jí)。熔斷之后第一次調(diào)用如果還是異常調(diào)用,則直接再次熔斷,不必判斷異常比例。官方解釋: 異常比例 (ERROR_RATIO):當(dāng)單位統(tǒng)計(jì)時(shí)長(zhǎng)(statIntervalMs)內(nèi)請(qǐng)求數(shù)目大于設(shè)置的最小請(qǐng)求數(shù)目,并且異常的比例大于閾值,則接下來(lái)的熔斷時(shí)長(zhǎng)內(nèi)請(qǐng)求會(huì)自動(dòng)被熔斷。經(jīng)過(guò)熔斷時(shí)長(zhǎng)后熔斷器會(huì)進(jìn)入探測(cè)恢復(fù)狀態(tài)(HALF-OPEN 狀態(tài)),若接下來(lái)的一個(gè)請(qǐng)求成功完成(沒(méi)有錯(cuò)誤)則結(jié)束熔斷,否則會(huì)再次被熔斷。異常比率的閾值范圍是 [0.0, 1.0],代表 0% - 100%。

異常數(shù)
在設(shè)定的最小請(qǐng)求的基礎(chǔ)上,出現(xiàn)異常次數(shù)大于異常數(shù),之后的請(qǐng)求則會(huì)熔斷降級(jí)。熔斷之后第一次調(diào)用如果還是異常調(diào)用,則直接再次熔斷,不必判斷異常數(shù)。
官方解釋: 異常數(shù) (ERROR_COUNT):當(dāng)單位統(tǒng)計(jì)時(shí)長(zhǎng)內(nèi)的異常數(shù)目超過(guò)閾值之后會(huì)自動(dòng)進(jìn)行熔斷。經(jīng)過(guò)熔斷時(shí)長(zhǎng)后熔斷會(huì)進(jìn)入探測(cè)恢復(fù)狀態(tài)(HALF-OPEN 狀態(tài)),若接下來(lái)的一個(gè)請(qǐng)求成功完成(沒(méi)有錯(cuò)誤)則結(jié)束熔斷,否則會(huì)再次被熔斷。注意:異常降級(jí)僅針對(duì)業(yè)務(wù)異常,對(duì) Sentinel 限流降級(jí)本身的異常(BlockException)不生效。

第八關(guān):openFeign跟Sentinel的整合
1. pom文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--nacos-服務(wù)注冊(cè)發(fā)現(xiàn)-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--1. 添加openfeign依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--sentinel依賴-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2.yaml配置文件
開(kāi)啟openFeign對(duì)sentinel的整合. Feign.sentinel.enabled = true
server:
port: 8041
# 應(yīng)用名稱 (nacos會(huì)將該名稱當(dāng)做服務(wù)名稱)
spring:
application:
name: order-service
cloud:
nacos:
server-addr: 192.168.2.101:8847
discovery:
username: nacos
password: nacos
namespace: public
feign:
sentinel:
# openfeign整合sentinel
enabled: true
3.feign接口補(bǔ)充實(shí)現(xiàn)類,進(jìn)行降級(jí)方法的補(bǔ)充
// feign 接口 指定降級(jí)類
@FeignClient(value="stock-nacos",path = "/stock",fallback = StockFeignServiceFallback.class)
public interface StockFeignService {
@RequestMapping("/reduct")
public String reduct2();
}
// feign的fallback實(shí)現(xiàn)類,實(shí)現(xiàn)降級(jí)方法
@Component
public class StockFeignServiceFallback implements StockFeignService {
@Override
public String reduct2() {
return "降級(jí)啦?。?!";
}
}
第九關(guān):熱點(diǎn)參數(shù)流控
何為熱點(diǎn)?
熱點(diǎn)即經(jīng)常訪問(wèn)的數(shù)據(jù)。很多時(shí)候我們希望統(tǒng)計(jì)某個(gè)熱點(diǎn)數(shù)據(jù)中訪問(wèn)頻次最高的數(shù)據(jù),并對(duì)其訪問(wèn)進(jìn)行限制。熱點(diǎn)參數(shù)限流會(huì)統(tǒng)計(jì)傳入?yún)?shù)中的熱點(diǎn)參數(shù),并根據(jù)配置的限流閾值與模式,對(duì)包含熱點(diǎn)參數(shù)的資源調(diào)用進(jìn)行限流。熱點(diǎn)參數(shù)限流可以看做是一種特殊的流量控制,僅對(duì)包含熱點(diǎn)參數(shù)的資源調(diào)用生效。
注意:
熱點(diǎn)規(guī)則需要使用@SentinelResource("resourceName")注解,否則不生效
參數(shù)必須是7種基本數(shù)據(jù)類型才會(huì)生效
單機(jī)閾值: 針對(duì)所有參數(shù)的值進(jìn)行設(shè)置的一個(gè)公共的閾值
假設(shè)當(dāng)前 參數(shù) 大部分的值都是熱點(diǎn)流量, 單機(jī)閾值就是針對(duì)熱點(diǎn)流量進(jìn)行設(shè)置, 額外針對(duì)普通流量進(jìn)行參數(shù)值流控
假設(shè)當(dāng)前 參數(shù) 大部分的值都是普通流量, 單機(jī)閾值就是針對(duì)普通流量進(jìn)行設(shè)置, 額外針對(duì)熱點(diǎn)流量進(jìn)行參數(shù)值流控
第十關(guān):Sentinel規(guī)則持久化
問(wèn)題
上述方法,在服務(wù)重啟之后,流控規(guī)則就被清空了,沒(méi)有數(shù)據(jù)持久化。
原始模式
如果不做任何修改,Dashboard 的推送規(guī)則方式是通過(guò) API 將規(guī)則推送至客戶端并直接更新到內(nèi)存中。這種做法的好處是簡(jiǎn)單,無(wú)依賴;壞處是應(yīng)用重啟規(guī)則就會(huì)消失,僅用于簡(jiǎn)單測(cè)試,不能用于生產(chǎn)環(huán)境。
拉模式( Pull )
pull 模式的數(shù)據(jù)源(如本地文件、RDBMS 等)一般是可寫(xiě)入的。使用時(shí)需要在客戶端注冊(cè)數(shù)據(jù)源:將對(duì)應(yīng)的讀數(shù)據(jù)源注冊(cè)至對(duì)應(yīng)的 RuleManager,將寫(xiě)數(shù)據(jù)源注冊(cè)至 transport 的WritableDataSourceRegistry 中。
推模式 ( Push )
生產(chǎn)環(huán)境下一般更常用的是 push 模式的數(shù)據(jù)源。對(duì)于 push 模式的數(shù)據(jù)源,如遠(yuǎn)程配置中心(ZooKeeper, Nacos, Apollo等等),推送的操作不應(yīng)由 Sentinel 客戶端進(jìn)行,而應(yīng)該經(jīng)控制臺(tái)統(tǒng)一進(jìn)行管理,直接進(jìn)行推送,數(shù)據(jù)源僅負(fù)責(zé)獲取配置中心推送的配置并更新到本地。因此推送規(guī)則正確做法應(yīng)該是 配置中心控制臺(tái) /Sentinel 控制臺(tái) → 配置中心 → Sentinel 數(shù)據(jù)源 → Sentinel,而不是經(jīng) Sentinel 數(shù)據(jù)源推送至配置中心。
持久化方法一:嵌入到代碼里
像 第三關(guān) Sentinel 集成 原生Spring 一樣,把流控、熔斷降級(jí)的規(guī)則寫(xiě)在代碼里。
持久化方法二:Nacos配置中心實(shí)現(xiàn)推送
1、nacos配置中心中配置流控規(guī)則
[
{
"resource": "TestResource",
"controlBehavior": 0,
"count": 10.0,
"grade": 1,
"limitApp": "default",
"strategy": 0
}
]
2、補(bǔ)充yml配置
server:
port: 8861
spring:
application:
name: order-sentinel
cloud:
sentinel:
transport:
dashboard: 192.168.2.101:8858
web-context-unify: false # 默認(rèn)將調(diào)用鏈路收斂, 導(dǎo)致鏈路流控效果無(wú)效
datasource:
flow-rule:
nacos:
server-addr: 192.168.2.101:8847
username: nacos
password: nacos
dataId: order-sentinel-flow-rule
groupId: SENTINEL_GROUP # 默認(rèn)的不用配置
data‐type: yaml
rule-type: flow
問(wèn)題:
nacos 配置這一套。如果從 sentinel-dashboard 設(shè)置流控、降級(jí)等操作,是不會(huì)同步到nacos配置文件里的,還需要手動(dòng)更改nacos里的配置。
至于可以怎么解決? 如果在控制臺(tái)設(shè)置了流控,nacos自動(dòng)同步,還需要研究源碼,查看方法。 但是確定是可以實(shí)現(xiàn)的。
