什么是服務(wù)雪崩效應(yīng)
服務(wù)雪崩效應(yīng)是一種因“服務(wù)提供者服務(wù)的不可用”(原因)導(dǎo)致“服務(wù)調(diào)用者服務(wù)不可用”(結(jié)果)潦牛,并將不可用逐漸放大的現(xiàn)象伞梯。如下圖所示
形成原因
服務(wù)雪崩的過程可以分為三個(gè)階段:
- 服務(wù)提供者不可用骗绕;
- 重試加大請(qǐng)求流量隅熙;
-
服務(wù)調(diào)用者不可用遍愿;
服務(wù)雪崩的每個(gè)階段都可能由不同的原因造成奔滑,總結(jié)如下:
image.png
應(yīng)對(duì)策略
常見容錯(cuò)方案:
1耙考、超時(shí)
2谜喊、限流
3、艙壁模式(如每個(gè)controller都有自己獨(dú)立的線程池倦始,之間互不干擾)
4斗遏、斷路器模式
全面應(yīng)對(duì)策略:
Sentinel 是什么
隨著微服務(wù)的流行,服務(wù)和服務(wù)之間的穩(wěn)定性變得越來越重要鞋邑。Sentinel阿里中間件團(tuán)隊(duì)開源的诵次,面向分布式服務(wù)架構(gòu)的輕量級(jí)高可用流量控制組件,主要以流量為切入點(diǎn)枚碗,從流量控制逾一、熔斷降級(jí)、系統(tǒng)負(fù)載保護(hù)等多個(gè)維度來幫助您保護(hù)服務(wù)的穩(wěn)定性肮雨。
大家可能會(huì)問:Sentinel 和之前常用的熔斷降級(jí)庫 Netflix Hystrix 有什么異同呢遵堵?Sentinel官網(wǎng)有一個(gè)對(duì)比的文章,這里摘抄一個(gè)總結(jié)的表格怨规,具體的對(duì)比可以點(diǎn)此 鏈接 查看陌宿。
對(duì)比內(nèi)容 | Sentinel | Hystrix |
---|---|---|
隔離策略 | 信號(hào)量隔離 | 線程池隔離/信號(hào)量隔離 |
熔斷降級(jí)策略 | 基于響應(yīng)時(shí)間或失敗比率 | 基于失敗比率 |
實(shí)時(shí)指標(biāo)實(shí)現(xiàn) | 滑動(dòng)窗口 | 滑動(dòng)窗口(基于 RxJava) |
規(guī)則配置 | 支持多種數(shù)據(jù)源 | 支持多種數(shù)據(jù)源 |
擴(kuò)展性 | 多個(gè)擴(kuò)展點(diǎn) | 插件的形式 |
基于注解的支持 | 支持 | 支持 |
限流 | 基于 QPS,支持基于調(diào)用關(guān)系的限流 | 不支持 |
流量整形 | 支持慢啟動(dòng)椅亚、勻速器模式 | 不支持 |
系統(tǒng)負(fù)載保護(hù) | 支持 | 不支持 |
控制臺(tái) | 開箱即用限番,可配置規(guī)則、查看秒級(jí)監(jiān)控呀舔、機(jī)器發(fā)現(xiàn)等 | 不完善 |
常見框架的適配 | Servlet、Spring Cloud、Dubbo媚赖、gRPC 等 | Servlet霜瘪、Spring Cloud Netflix |
從對(duì)比的表格可以看到,Sentinel比Hystrix在功能性上還要強(qiáng)大一些惧磺,本文讓我們一起來了解下Sentinel的源碼颖对,揭開Sentinel的神秘面紗。
Sentinel功能特點(diǎn)
1磨隘、豐富的應(yīng)用場景:例如秒殺(即突發(fā)流量控制在系統(tǒng)容量可以承受的范圍)缤底、消息削峰填谷、集群流量控制番捂、實(shí)時(shí)熔斷下游不可用應(yīng)用等
2个唧、完備的實(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)行情況徙歼。
3、廣泛的開源生態(tài):Sentinel 提供開箱即用的與其它開源框架/庫的整合模塊鳖枕,例如與 Spring Cloud魄梯、Dubbo、gRPC 的整合宾符。您只需要引入相應(yīng)的依賴并進(jìn)行簡單的配置即可快速地接入 Sentinel酿秸。
4、完善的 SPI 擴(kuò)展點(diǎn):Sentinel 提供簡單易用魏烫、完善的 SPI 擴(kuò)展接口辣苏。您可以通過實(shí)現(xiàn)擴(kuò)展接口來快速地定制邏輯。例如定制規(guī)則管理则奥、適配動(dòng)態(tài)數(shù)據(jù)源等考润。
開源生態(tài)
Sentinel 分為兩個(gè)部分:
核心庫(Java 客戶端)不依賴任何框架/庫,能夠運(yùn)行于所有 Java 運(yùn)行時(shí)環(huán)境读处,同時(shí)對(duì) Dubbo / Spring Cloud 等框架也有較好的支持糊治。
控制臺(tái)(Dashboard)基于 Spring Boot 開發(fā),打包后可以直接運(yùn)行罚舱,不需要額外的 Tomcat 等應(yīng)用容器井辜。
為應(yīng)用整合Sentinel
引入maven依賴
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<!--sentinel整合之后會(huì)暴露出/actuator/sentinel-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!--整合Spring Cloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--整合Spring Cloud Alibaba-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.9.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
加入配置暴露/actuator/sentinel端點(diǎn)
#添加sentinel依賴后 暴露/actuator/sentinel端點(diǎn)
management:
endpoints:
web:
exposure:
include: '*'
啟動(dòng)服務(wù)訪問http://localhost:port/actuator/sentinel會(huì)返回json信息,說明已經(jīng)整合好了Sentinel
搭建Sentinel控制臺(tái)
下載Sentinel控制臺(tái):https://github.com/alibaba/Sentinel/releases
為服務(wù)整合Sentinel控制臺(tái):
spring:
cloud:
sentinel:
filter:
#打開/關(guān)閉掉對(duì)Spring MVC端點(diǎn)的保護(hù)
enabled: true
transport:
port: 8719
#指定sentinel控制臺(tái)的地址
dashboard: localhost:8080
定義資源:也就是對(duì)哪個(gè)資源進(jìn)行流量控制管闷,現(xiàn)在已經(jīng)提供了注解形式粥脚,所以新的接入直接用注解,@SentinelResource
- 關(guān)于SentinelResource注解包个,這里列出幾個(gè)好用和必填的參數(shù)刷允,具體參考這里
Sentinel控制臺(tái)配置流控規(guī)則
流控模式
- 直接:當(dāng)QPS超過閾值就進(jìn)行限流。
- 關(guān)聯(lián):當(dāng)關(guān)聯(lián)的資源達(dá)到閾值,就限流自己树灶。
- 適用場景:查詢和修改同一表的數(shù)據(jù)纤怒,如果是高并發(fā)的應(yīng)用,查詢接口的流量過大天通,就會(huì)影響修改接口的性能泊窘,反之同理,這就可以根據(jù)業(yè)務(wù)需求像寒,去衡量希望優(yōu)先讀還是優(yōu)先寫烘豹。
- 關(guān)聯(lián)其實(shí)是一種保護(hù)關(guān)聯(lián)資源的設(shè)計(jì)。
- 鏈路:只記錄指定鏈路上的流量诺祸,即指定資源從入口資源進(jìn)來的流量如果達(dá)到閾值就限流携悯。
- 鏈路其實(shí)是一種細(xì)粒度的針對(duì)來源,而編輯流控規(guī)則中的針對(duì)來源輸入框是微服務(wù)級(jí)別的序臂,可以指定指定微服務(wù)過來的流量達(dá)到閾值就限流蚌卤。
- 而鏈路是api級(jí)別的,指定的是api的調(diào)用流量達(dá)到閾值就限流奥秆。
流控效果
- 快速失斞放怼:直接失敗,拋異常
相關(guān)源碼:com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController - Warm Up(預(yù)熱):根據(jù)codeFactor(冷加載因子构订,默認(rèn)值為3)侮叮,從閾值/codeFactor,經(jīng)過預(yù)熱時(shí)長悼瘾,才達(dá)到設(shè)置的QPS閾值囊榜。
即如果閾值為100,冷加載因子為3亥宿,預(yù)熱時(shí)長為10秒卸勺,那么就會(huì)用100 / 3作為最初的閾值,經(jīng)過10秒之后才會(huì)將閾值達(dá)到100烫扼,進(jìn)而進(jìn)行限流曙求,意思就是讓允許通過的流量緩慢增加,在達(dá)到一定的時(shí)間之后才達(dá)到閾值這樣會(huì)更好的保護(hù)微服務(wù) - 排隊(duì)等待:勻速排隊(duì)映企,讓請(qǐng)求以均勻的速度通過悟狱,閾值類型必須設(shè)置成QPS,否則無效堰氓。此種模式可適用于應(yīng)對(duì)突發(fā)流量的場景
相關(guān)源碼:com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController
Sentinel控制臺(tái)配置降級(jí)規(guī)則挤渐,即斷路器模式,Sentinel目前只有斷路器三態(tài)中的打開和關(guān)閉双絮,沒有半開狀態(tài)
降級(jí)策略
-
RT:平均響應(yīng)時(shí)間
注意:Sentinel默認(rèn)RT最大時(shí)間為4900毫秒浴麻,可通過-Dcsp.sentinel.statistic.max.rt=xxx修改
image.png -
異常比例
image.png -
異常數(shù)
注意:時(shí)間窗口<60秒可能會(huì)出問題
相關(guān)源碼:com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule
image.png
image.png
Sentinel控制臺(tái)配置熱點(diǎn)規(guī)則得问,是一種特殊的流控規(guī)則,支持對(duì)特定的參數(shù)和參數(shù)的值限流
適用于存在熱點(diǎn)參數(shù)(某些參數(shù)QPS很高)白胀,并希望提升API可用性的場景
注意:參數(shù)必須是基本類型或者String
相關(guān)源碼:com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowChecker#passCheck()
加入代碼
@GetMapping("/test-hot")
@SentinelResource("hot")
public String testHot(@RequestParam(required = false) String a,
@RequestParam(required = false)String b){
return a + ":" + b;
}
Sentinel控制臺(tái)配置系統(tǒng)規(guī)則
閾值類型
- LOAD
當(dāng)系統(tǒng)Load1(1分鐘的load)超過閾值椭赋,且并發(fā)線程數(shù)超過系統(tǒng)容量時(shí)觸發(fā)抚岗,建議配置為CPU核心數(shù)*2.5或杠。(僅對(duì)Linux/Unix-like 機(jī)器生效)
系統(tǒng)容量 = maxQps * minRt
maxQps:秒級(jí)統(tǒng)計(jì)出來的最大QPS
minRt:秒級(jí)統(tǒng)計(jì)出來的最小響應(yīng)時(shí)間
相關(guān)源碼:com.alibaba.csp.sentinel.slots.system.SystemRuleManager#checkBbr() - RT:所有入口流量的平均RT達(dá)到閾值觸發(fā)
- 線程數(shù):所有入口流量的并發(fā)線程數(shù)達(dá)到閾值觸發(fā)
-
入口QPS:所有入口流量的QPS達(dá)到閾值觸發(fā)
相關(guān)源碼:com.alibaba.csp.sentinel.slots.system.SystemRuleManager#checkSystem()
image.png
Sentinel控制臺(tái)配置授權(quán)規(guī)則
- 白名單:資源名里的資源只允許為白名單里面的流控應(yīng)用訪問。
- 黑名單:資源名里的資源不允許為黑名單里面的流控應(yīng)用訪問宣蔚。
- 授權(quán)規(guī)則通過調(diào)用來源從而實(shí)現(xiàn)對(duì)服務(wù)消費(fèi)者的授權(quán)或者限制向抢。
Sentinel使用Java代碼方式配置規(guī)則
請(qǐng)點(diǎn)擊:
Alibaba Sentinel 規(guī)則參數(shù)總結(jié)
Alibaba Sentinel 配置項(xiàng)總結(jié)
Sentinel與控制臺(tái)通信原理剖析
微服務(wù)注冊到Sentinel控制臺(tái)和發(fā)送心跳源碼:com.alibaba.csp.sentinel.transport.heartbeat.SimpleHttpHeartbeatSender
微服務(wù)和Sentinel控制臺(tái)通信API源碼:com.alibaba.csp.sentinel.command.CommandHandler接口的實(shí)現(xiàn)類
修改控制臺(tái)規(guī)則是如何通知客戶端的?
看sentinel-transport-simple-http包中的HttpEventTask類胚委,它開啟了一個(gè)線程挟鸠,專門用來做為socket連接,控制臺(tái)通過socket請(qǐng)求通知客戶端亩冬,從而更新客戶端規(guī)則艘希,更改規(guī)則核心代碼如下:
long start = System.currentTimeMillis();
in = new BufferedReader(new InputStreamReader(this.socket.getInputStream(), SentinelConfig.charset()));
OutputStream outputStream = this.socket.getOutputStream();
printWriter = new PrintWriter(new OutputStreamWriter(outputStream, Charset.forName(SentinelConfig.charset())));
String line = in.readLine();
CommandCenterLog.info("[SimpleHttpCommandCenter] socket income: " + line + "," + this.socket.getInetAddress(), new Object[0]);
CommandRequest request = this.parseRequest(line);
String commandName = HttpCommandUtils.getTarget(request);
if (!StringUtil.isBlank(commandName)) {
CommandHandler<?> commandHandler = SimpleHttpCommandCenter.getHandler(commandName);
if (commandHandler != null) {
CommandResponse<?> response = commandHandler.handle(request);
this.handleResponse(response, printWriter, outputStream);
} else {
this.badRequest(printWriter, "Unknown command `" + commandName + '`');
}
printWriter.flush();
long cost = System.currentTimeMillis() - start;
CommandCenterLog.info("[SimpleHttpCommandCenter] Deal a socket task: " + line + ", address: " + this.socket.getInetAddress() + ", time cost: " + cost + " ms", new Object[0]);
return;
}
this.badRequest(printWriter, "Invalid command");
Sentinel配置項(xiàng)
微服務(wù)應(yīng)用端連接Sentinel控制臺(tái)配置項(xiàng)
spring.cloud.sentinel.transport:
# 指定控制臺(tái)的地址
dashboard:localhost:8080
# 指定和控制臺(tái)通信的IP
# 如不配置,會(huì)自動(dòng)選擇一個(gè)IP注冊
client-ip:127.0.0.1
# 指定和控制臺(tái)通信的端口硅急,默認(rèn)8719
# 如不設(shè)置覆享,會(huì)自動(dòng)從8719開始掃描,依次+1营袜,直到找到未被占用的端口
port:8719
# 心跳發(fā)送周期撒顿,默認(rèn)值null
# 但在SimpleHttpHeartbeatSender會(huì)用默認(rèn)值10秒
heartbeat-interval-ms:1000
Sentinel控制臺(tái)配置項(xiàng)
配置項(xiàng) | 默認(rèn)值 | 最小值 | 描述 |
---|---|---|---|
sentinel.dashboard.app.hideAppNoMachineMillis | 0 | 60000 | 是否隱藏?zé)o健康節(jié)點(diǎn)的應(yīng)用,距離最近 一次主機(jī)心跳時(shí)間的毫秒數(shù)荚板,默認(rèn)關(guān)閉 |
sentinel.dashboard.removeAppNoMachineMillis | 0 | 120000 | 是否自動(dòng)刪除無健康節(jié)點(diǎn)的應(yīng)用凤壁,距離 最近一次其下節(jié)點(diǎn)心跳時(shí)間毫秒數(shù),默 認(rèn)關(guān)閉 |
sentinel.dashboard.unhealthyMachineMillis | 60000 | 30000 | 主機(jī)失聯(lián)判定跪另,不可關(guān)閉 |
sentinel.dashboard.autoRemoveMachineMillis | 0 | 300000 | 距離最近心跳時(shí)間超過指定時(shí)間是否 自動(dòng)刪除失聯(lián)節(jié)點(diǎn)拧抖,默認(rèn)關(guān)閉 |
server.port | 8080 | - | 指定端口 |
csp.sentinel.dashboard.server | localhost:8080 | - | 指定地址 |
project.name | - | - | 指定程序名稱 |
sentinel.dashboard.auth.username[1.6] | sentinel | - | dashboard登錄賬號(hào) |
sentinel.dashboard.auth.password[1.6] | sentinel | - | dashboard登錄密碼 |
server.servlet.session.timeout[1.6] | 30分鐘 | - | 登錄session過期時(shí)間 配置為 7200表示7200秒 配置為60m表示為60分鐘 |
Sentinel API
- Sphu:定義資源,讓資源受到監(jiān)控并保護(hù)資源免绿。
- Tracer:可以對(duì)我們想要的異常進(jìn)行統(tǒng)計(jì)唧席。
- ContextUtil:可以實(shí)現(xiàn)調(diào)用來源,還可以標(biāo)記調(diào)用针姿。
@GetMapping("/test-sentinel-api")
public String testSentinelAPI(@RequestParam(required = false) String a){
String resourceName = "test-sentinel-api";
ContextUtil.enter(resourceName,"test-wfw");
Entry entry = null;
try {
//定義一個(gè)sentinel保護(hù)的資源 名稱是test-sentinel-api
entry = SphU.entry(resourceName);
//被保護(hù)的業(yè)務(wù)邏輯
if(StringUtils.isEmpty(a)){
throw new IllegalArgumentException("a不能為空");
}
return a;
} catch (BlockException e) {
//如果被保護(hù)的資源被限流或者降級(jí)了袱吆,就會(huì)拋BlockException
log.warn("限流,或者降級(jí)了...",e);
return "限流距淫,或者降級(jí)了...";
}catch (IllegalArgumentException e) {
//統(tǒng)計(jì)IllegalArgumentException發(fā)生的次數(shù)绞绒,發(fā)生的占比等
Tracer.trace(e);
return "參數(shù)非法...";
} finally {
if(entry != null){
//退出entry
entry.exit();
}
ContextUtil.exit();
}
}
Sentinel @SentinelResource詳解
@SentinelResource使用方式一
//使用blockHandler屬性,blockHandler的方法必須和資源在同一類中榕暇,并且有相同的參數(shù)和返回值
@PostMapping
@SentinelResource(value = "createOrder",blockHandler = "doOnBlock")
public OrderInfo create(@RequestBody OrderInfo order, @AuthenticationPrincipal String username){
log.info("用戶名為:username={}",username);
PriceInfo priceInfo = priceFeignClient.getPrice(order.getProductId());
log.info("商品價(jià)格為,priceInfo={}",priceInfo);
return order;
}
public OrderInfo doOnBlock(@RequestBody OrderInfo order, @AuthenticationPrincipal String username, BlockException exception){
log.info("blocked by :blockException={}",exception.getClass().getSimpleName());
return order;
}
@SentinelResource使用方式二
@PostMapping
@SentinelResource(value = "createOrder",blockHandler = "doOnBlock",blockHandlerClass = SentinelBlockHandler.class)
public OrderInfo create(@RequestBody OrderInfo order, @AuthenticationPrincipal String username){
log.info("用戶名為:username={}",username);
PriceInfo priceInfo = priceFeignClient.getPrice(order.getProductId());
log.info("商品價(jià)格為,priceInfo={}",priceInfo);
return order;
}
@Slf4j
public class SentinelBlockHandler {
public static OrderInfo doOnBlock(@RequestBody OrderInfo order, @AuthenticationPrincipal String username, BlockException exception){
log.info("blocked by :blockException={}",exception.getClass().getSimpleName());
return order;
}
}
@SentinelResource其與屬性和新增屬性
屬性 | 作用 | 是否必須 |
---|---|---|
value | 資源名稱 | 是 |
entryType | entry類型蓬衡,標(biāo)記流量的方向喻杈,取值IN/OUT,默認(rèn)是OUT | 否 |
blockHandler | 處理BlockException的函數(shù)名稱狰晚。函數(shù)要求: 1. 必須是 public 2.返回類型與原方法一致 3. 參數(shù)類型需要和原方法相匹配筒饰,并在最后加 BlockException 類型 的參數(shù)。 4. 默認(rèn)需和原方法在同一個(gè)類中壁晒。若希望使用其他類的函數(shù)瓷们,可配置 blockHandlerClass ,并指定blockHandlerClass里面的方法秒咐。 |
否 |
blockHandlerClass | 存放blockHandler的類谬晕。對(duì)應(yīng)的處理函數(shù)必須static修飾, 否則無法解析携取,其他要求:同blockHandler攒钳。 |
否 |
fallback | 用于在拋出異常的時(shí)候提供fallback處理邏輯。fallback函數(shù)可以針對(duì) 所有類型的異常(除了 exceptionsToIgnore 里面排除掉的異常類型) 進(jìn)行處理雷滋。函數(shù)要求: 1. 返回類型與原方法一致 2. 參數(shù)類型需要和原方法相匹配不撑,Sentinel 1.6開始, 也可在方法最后加 Throwable 類型的參數(shù)晤斩。 3.默認(rèn)需和原方法在同一個(gè)類中焕檬。若希望使用其他類的函數(shù), 可配置 fallbackClass 尸昧,并指定fallbackClass里面的方法揩页。 |
否 |
fallbackClass【1.6】 | 存放fallback的類。對(duì)應(yīng)的處理函數(shù)必須static修飾烹俗, 否則無法解析爆侣,其他要求:同fallback。 |
否 |
defaultFallback【1.6】 | 用于通用的 fallback 邏輯幢妄。默認(rèn)fallback函數(shù)可以針對(duì)所有類型的 異常(除了 exceptionsToIgnore 里面排除掉的異常類型)進(jìn)行處理兔仰。 若同時(shí)配置了 fallback 和defaultFallback,以fallback為準(zhǔn)蕉鸳。 函數(shù)要求:1. 返回類型與原方法一致 2. 方法參數(shù)列表為空乎赴,或者有一個(gè) Throwable 類型的參數(shù)。 3. 默認(rèn)需要和原方法在同一個(gè)類中潮尝。若希望使用其他類的函數(shù)榕吼, 可配置 fallbackClass ,并指定 fallbackClass 里面的方法勉失。 |
否 |
exceptionsToIgnore【1.6】 | 指定排除掉哪些異常羹蚣。排除的異常不會(huì)計(jì)入異常統(tǒng)計(jì), 也不會(huì)進(jìn)入fallback邏輯乱凿,而是原樣拋出顽素。 |
否 |
exceptionsToTrace | 需要trace的異常 | Throwable |
@SentinelResource相關(guān)源碼
com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect
com.alibaba.csp.sentinel.annotation.aspectj.AbstractSentinelAspectSupport
RestTemplate整合Sentinel
@Bean
@LoadBalanced
@SentinelRestTemplate
public RestTemplate RestTemplate(){
return new RestTemplate(new HttpComponentsClientHttpRequestFactory());
}
resttemplate:
sentinel:
#false 關(guān)閉@SentinelRestTemplate注解咽弦,在做開發(fā)調(diào)試的時(shí)候可以關(guān)閉此注解,專注于功能的實(shí)現(xiàn)
enabled: true
相關(guān)源碼:org.springframework.cloud.alibaba.sentinel.custom.SentinelBeanPostProcessor
Feign整合Sentinel
feign:
sentinel:
#為feign整合Sentinel
enabled: true
發(fā)生限流降級(jí)時(shí)胁出,自定義處理邏輯
使用@FeignClient的fallback屬性
@FeignClient(value="priceServer",fallback = PriceFeignClientFallback.class)
public interface PriceFeignClient {
@GetMapping(value = "/prices/{id}")
PriceInfo getPrice(@PathVariable("id") Integer id);
}
/**
* 發(fā)生限流降級(jí)時(shí)型型,自定義處理邏輯
*
* 一旦PriceFeignClient中遠(yuǎn)程調(diào)用的getPrice()方法被流控了或發(fā)生異常了,就會(huì)進(jìn)入此方法
* 這就相當(dāng)于一個(gè)兜底的行為全蝶,保證了服務(wù)的可用
*/
@Component
public class PriceFeignClientFallback implements PriceFeignClient {
@Override
public PriceInfo getPrice(Integer id) {
PriceInfo priceInfo = new PriceInfo();
priceInfo.setId(id);
priceInfo.setPrice(new BigDecimal(id));
return priceInfo;
}
}
使用@FeignClient的fallbackFactory屬性闹蒜,推薦使用這種方案
@FeignClient(value="priceServer",fallbackFactory = PriceFeignClientFallbackFactory.class)
public interface PriceFeignClient {
@GetMapping(value = "/prices/{id}")
PriceInfo getPrice(@PathVariable("id") Integer id);
}
/**
* 發(fā)生限流降級(jí)時(shí),自定義處理邏輯
* 一旦PriceFeignClient中遠(yuǎn)程調(diào)用的getPrice()方法被流控了或發(fā)生異常了裸诽,就會(huì)進(jìn)入此方法
* 這就相當(dāng)于一個(gè)兜底的行為嫂用,保證了服務(wù)的可用
* 相比于FeignClient中的fallback屬性而言,fallbackFactory屬性在fallback的基礎(chǔ)上可以拿到異常信息
*/
@Component
@Slf4j
public class PriceFeignClientFallbackFactory implements FallbackFactory<PriceFeignClient> {
@Override
public PriceFeignClient create(Throwable throwable) {
return new PriceFeignClient() {
@Override
public PriceInfo getPrice(Integer id) {
log.error("遠(yuǎn)程調(diào)用被限流或降級(jí)了丈冬,throwable={}",throwable);
PriceInfo priceInfo = new PriceInfo();
priceInfo.setId(id);
priceInfo.setPrice(new BigDecimal(id));
return priceInfo;
}
};
}
}
相關(guān)源碼:org.springframework.cloud.alibaba.sentinel.feign.SentinelFeign
Sentinel使用方式總結(jié)
使用方式 | 使用方式 | 使用方法 |
---|---|---|
編碼方式 | API | try...catch...finally |
注解方式 | @SentinelResource | blockHandler / fallback |
RestTemplate | @SentinelRestTemplate | blockHandler / fallback |
Feign | feign.sentinel.enabled=true | fallback / fallbackFactory |
Sentinel規(guī)則持久化方案推薦:
Alibaba Sentinel規(guī)則持久化-推模式-手把手教程【基于Nacos】
https://github.com/eacdy/Sentinel-Dashboard-Nacos/releases
https://github.com/alibaba/Sentinel/wiki/在生產(chǎn)環(huán)境中使用-Sentinel#pull模式
參考: