Java之SpringCloud Alibaba【四】【微服務 Sentinel服務熔斷】
- 一、分布式系統遇到的問題
- 1、服務掛掉的一些原因
- 二、解決方案
- 三、Sentinel:分布式系統的流量防衛兵
- 1、Sentinel是什么
- 2、Sentinel和Hystrix對比
- 3、Sentinel快速開發
- 4、通過注解的方式來控流
- 5、啟動Sentinel控制臺
- 四、Spring Cloud Alibaba 整合Sentinel
- 1、復制創建項目并,引入依賴
- 2、完善代碼
- 3、啟動測試
- 五、Sentinel流控規則
- 1、實時監控
- 2、簇點鏈路
- 六、流控規則
- 1、流量控制(iow conrol)
- 2、QPS
- 3、并發線程數
- 4、BlockException異常統一處理
- 七、流控模式
- 1、直接
- 2、關聯
- 3、鏈路
- 八、流控效果
- 1、Warm Up(激增流量)預熱冷啟動
- 2、均勻排隊(脈沖流量)
- 九、降級規則
- 1、熔斷策略:慢調用比例(LO_REOESLRATO):
- 2、熔斷策略:異常比例
- 3、熔斷策略:異常數
一、分布式系統遇到的問題
1、服務掛掉的一些原因
如果其中的下單服務不可用,就會出現線程池里所有線程都因等待響應而被阻塞,從而造成整個服務鏈路不可用,進而導致整個系統的服務雪崩.如圖所示;
服務雪崩效應:因服務提供者的不可用導致服務調用者的不可用,并將不可用逐漸放大的過程,就叫服務雪崩效應導致服務不可用的原因:
二、解決方案
穩定性、恢復性
Reliability && Resilience
常見的容錯機制:
超時機制
在不做任何處理的情況下,服務提供者不可用會導致消費者請求線程強制等待,而造成系統資源耗盡。加入超時機制,一旦超時,就釋放資源。由于釋放資源速度較快,一定程度上可以抑制資源耗盡的問題。服務限流
隔離
原理:用戶的請求將不再直接訪問服務,而是通過線程池中的空閑線程來訪問服務,如果線程池已滿,則會進行降級處理,用戶的請求不會被阻塞,至少可以看到一個執行鋅果(例如返回友好的提示信息),而不是無休止的等待或者看到系統崩潰。
隔離前:
b)信號隔離
信號隔離也可以甲于限制并發訪問,防止阻塞擴散、與線租隔離最大不同在于執行依賴代碼的線程依然是請求線程(該線程需要通過信號申請,如果客戶端是可信的且可以快速返回,可以使用信號隔離替換線程隔離,降低開銷。信號量的大小可以動態調整,線程池大小不可以。
- 服務熔斷
遠程服務不穩定或網絡抖動時暫時關閉,就叫服務熔斷。
現實世界的斷路器大家肯定都很了解,斷路器實時監控電路的情況,如果發現電路電流異常,就會跳閘,從而防止電路被燒毀。
軟件世界的斷路器可以這樣理解︰實時監測應用,如果發現在一定時間內失敗次數失敗率達到一定閾值,就"跳閘”,斷路器打開——此時,請求直接返回,而不去調用原本調用的邏輯。
跳閘一段時間后(例如10秒),斷路器會進入半開狀態,這是一個瞬間態,此時允許一次請求調用該調的邏輯,如果成功,則斷路器關閉,應用正常調用;如果調用依然不成功,斷路器繼續回到打開狀態,過段時間再進入半開狀態嘗試——通過"跳閘,應用可以保護自己,而且避免浪費資源;而通過半開的設計,可實現應用的"自我修復"。
所以,同樣的道理,當依賴的服務有大量超時時,在讓新的請求去訪問根本沒有意義,只會無畏的消耗現有資源。
比如我們設置了超時時間為1s.如果短時間內有大量請求在1s內都得不到響應,就意味著這個服務出現了異常,此時就沒有必要再讓其他的請求去訪問這個依賴了,這個時候就應該使用斷路器避免資源浪費。
- 服務降級
有服務熔斷,必然要有服務降級。
所謂降級,就是當某個服務熔斷之后,服務將不再被調用,此時客戶端可以自己準備一個本地的tllack(回退)回調,返回一個缺省值。例如:(備用接口緩存/mok數據)。
這樣做,雖然服務水平下降,但好歹可用,比直接掛掉要強,當然這也要看適合的業務場景。
三、Sentinel:分布式系統的流量防衛兵
1、Sentinel是什么
隨著微服務的流行,服務和服務之間的穩定性變得越來越重要。Sentinel是面向分布式服務架構的流量控制組件,主要以流量為切入點,從限流、流量整形、熔斷降級、系統負
載保護、熱點防護等多
個維度來幫助開發者保障微服務的穩定性。
源碼地址: https://github.com/alibaba/Sentinel
官方文檔: https://github.com/alibaba/Sentinel/wiki
Sentinel具有以下特征:
- 豐富的應用場景: Sentinel承接了阿里巴巴近10年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的范圍)、消息削峰填谷、實時熔
斷下游不可用應用等。 - 完備的實時監控:Sentinel同時提供實時的監控功能。您可以在控制臺中看到接入應用的單臺機器秒級數據,甚至50O臺以下規模的集群的匯總運行情況。
- 廣泛的開源生態:Sentinel提供開箱即用的與其它開源框架庫的整合模塊,例如與Spring Cloud、 Dubbo、gRPC的整合。您只需要引入相應的依賴并進行簡單的配置
置即可快速地接入
Sentinel。 - 完善的SPI擴展點: Sentinel 提供簡單易用、完善的SPI擴展點。您可以通過實現擴展點,快速的定制邏輯。例如定制規則管理、適配數據源等。
阿里云提供了企業級的Sentinel
服務,應用高可用服務AHAS
。
2、Sentinel和Hystrix對比
3、Sentinel快速開發
在官方文檔中,定義的Sentinel進行資源保護的幾個步驟:
1.定義資源
2.定義規則
3.檢驗規則是否生效
完善pom文件
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--sentinel核心庫--><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-core</artifactId><version>1.8.0</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.18</version></dependency><!--如果要使用@SentinelResourece--><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-annotation-aspectj</artifactId><version>1.8.0</version></dependency></dependencies>
package com.itbluebox.sentinelnew.controller;import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.PostConstruct;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;/**** @Author 徐庶 QQ:1092002729* @Slogan 致敬大師,致敬未來的你*/
@RestController
@Slf4j
public class HelloController {private static final String RESOURCE_NAME = "hello";private static final String USER_RESOURCE_NAME = "user";private static final String DEGRADE_RESOURCE_NAME = "degrade";// 進行sentinel流控@RequestMapping(value = "/hello")public String hello() {Entry entry = null;try {// 1.sentinel針對資源進行限制的entry = SphU.entry(RESOURCE_NAME);// 被保護的業務邏輯String str = "hello world";log.info("====="+str+"=====");return str;} catch (BlockException e1) {// 資源訪問阻止,被限流或被降級//進行相應的處理操作log.info("block!");return "被流控了!";} catch (Exception ex) {// 若需要配置降級規則,需要通過這種方式記錄業務異常Tracer.traceEntry(ex, entry);} finally {if (entry != null) {entry.exit();}}return null;}/*** 定義規則** spring 的初始化方法*/@PostConstruct //private static void initFlowRules(){// 流控規則List<FlowRule> rules = new ArrayList<>();// 流控FlowRule rule = new FlowRule();// 為哪個資源進行流控rule.setResource(RESOURCE_NAME);// 設置流控規則 QPSrule.setGrade(RuleConstant.FLOW_GRADE_QPS);// 設置受保護的資源閾值// Set limit QPS to 20.rule.setCount(1);rules.add(rule);// 通過@SentinelResource來定義資源并配置降級和流控的處理方法FlowRule rule2 = new FlowRule();//設置受保護的資源rule2.setResource(USER_RESOURCE_NAME);// 設置流控規則 QPSrule2.setGrade(RuleConstant.FLOW_GRADE_QPS);// 設置受保護的資源閾值// Set limit QPS to 20.rule2.setCount(1);rules.add(rule2);// 加載配置好的規則FlowRuleManager.loadRules(rules);}@PostConstruct // 初始化public void initDegradeRule(){/*降級規則 異常*/List<DegradeRule> degradeRules = new ArrayList<>();DegradeRule degradeRule = new DegradeRule();degradeRule.setResource(DEGRADE_RESOURCE_NAME);// 設置規則側率: 異常數degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);// 觸發熔斷異常數 : 2degradeRule.setCount(2);// 觸發熔斷最小請求數:2degradeRule.setMinRequestAmount(2);// 統計時長: 單位:ms 1分鐘degradeRule.setStatIntervalMs(60*1000); // 時間太短不好測// 一分鐘內: 執行了2次 出現了2次異常 就會觸發熔斷// 熔斷持續時長 : 單位 秒// 一旦觸發了熔斷, 再次請求對應的接口就會直接調用 降級方法。// 10秒過了后——半開狀態: 恢復接口請求調用, 如果第一次請求就異常, 再次熔斷,不會根據設置的條件進行判定degradeRule.setTimeWindow(10);degradeRules.add(degradeRule);DegradeRuleManager.loadRules(degradeRules);/*慢調用比率--DEGRADE_GRADE_RTdegradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);degradeRule.setCount(100);degradeRule.setTimeWindow(10);//請求總數小于minRequestAmount時不做熔斷處理degradeRule.setMinRequestAmount(2);// 在這個時間段內2次請求degradeRule.setStatIntervalMs(60*1000*60); // 時間太短不好測// 慢請求率:慢請求數/總請求數> SlowRatioThreshold ,// 這里要設置小于1 因為慢請求數/總請求數 永遠不會大于1degradeRule.setSlowRatioThreshold(0.9);*/}}
設置配置文件
server:port: 8060
訪問:http://localhost:8060/hello
不斷刷新頁面
4、通過注解的方式來控流
@Data
public class User {private final String username;
}
/*** @SentinelResource 改善接口中資源定義和被流控降級后的處理方法* 怎么使用: 1.添加依賴<artifactId>sentinel-annotation-aspectj</artifactId>* 2.配置bean——SentinelResourceAspect* value 定義資源* blockHandler 設置 流控降級后的處理方法(默認該方法必須聲明在同一個類)* 如果不想在同一個類中 blockHandlerClass 但是方法必須是static* fallback 當接口出現了異常,就可以交給fallback指定的方法進行處理* 如果不想在同一個類中 fallbackClass 但是方法必須是static** blockHandler 如果和fallback同時指定了,則blockHandler優先級更高* 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) {return new User("xushu");}public User fallbackHandleForGetUser(String id,Throwable e) {e.printStackTrace();return new User("異常處理");}/*** 注意:* 1. 一定要public* 2. 返回值一定要和源方法保證一致, 包含源方法的參數。* 3. 可以在參數最后添加BlockException 可以區分是什么規則的處理方法* @param id* @param ex* @return*/public User blockHandlerForGetUser(String id, BlockException ex) {ex.printStackTrace();return new User("流控!!");}@RequestMapping("/degrade")@SentinelResource(value = DEGRADE_RESOURCE_NAME,entryType = EntryType.IN,blockHandler = "blockHandlerForFb")public User degrade(String id) throws InterruptedException {// 異常數\比例throw new RuntimeException("異常");/* 慢調用比例TimeUnit.SECONDS.sleep(1);return new User("正常");*/}public User blockHandlerForFb(String id, BlockException ex) {return new User("熔斷降級");}
對應的依賴我們已經添加過了
重新運行并訪問
多次刷新
5、啟動Sentinel控制臺
下載控制臺jar包并在本地啟動
下載地址:https://github.com/alibaba/Sentinel/releases
運行jar
java -jar sentinel-dashboard-1.8.0.jar
運行成功
訪問:127.0.0.1:8080
用戶名:sentinel
密碼:sentinel
用戶可以通過如下參數進行配置
java -Dsentinel.dashboard.auth.username=sentinel sentinel-dashboard-1.8.0.jar #用于指定控制臺用戶名
java -Dsentinel.dashboard.auth.password=123456 sentinel-dashboard-1.8.0.jar #用于指定控制臺密碼
java -Dserver.servlet.session.timeout=8858 sentinel-dashboard-1.8.0.jar #用于指定Spring Boot端口
為了方便快捷啟動可以在桌面創建.bat
文件
java -Dserver.port=8858 -Dsentinel.dashboard.auth.username=xushu -Dsentinel.dashboard.auth.password=123456 -jar C:\Users\ZHENG\Desktop\sentinel-dashboard-1.8.0.jar
訪問:http://127.0.0.1:8858/
輸入上述設置的賬號和密碼
賬號:xushu
密碼:123456
登錄成功
流控規則設置可以通過Sentinel dashboard配置
客戶端需要引入Transport 模塊來與Sentinel 控制臺進行通信
<!--整合控制臺--><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-transport-simple-http</artifactId><version>1.8.0</version></dependency>
四、Spring Cloud Alibaba 整合Sentinel
1、復制創建項目并,引入依賴
<artifactId>order-sentinel</artifactId>
<module>order-sentinel</module>
<!-- sentinel 啟動器 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency>
記住啟動要Sentinel
2、完善代碼
@SpringBootApplication
public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class);}
}
@RestController
@RequestMapping("/order")
public class OrderController {@RequestMapping("/add")public String add(){System.out.println("下單成功");return "Hello world";}
}
3、啟動測試
訪問一下:http://localhost:8861/
然后訪問:http://127.0.0.1:8858/
不斷訪問:http://localhost:8861/order/add
五、Sentinel流控規則
1、實時監控
2、簇點鏈路
創建一個新接口
@GetMapping("/flow")public String flow(){return "正常訪問";}
重新啟動
訪問:http://localhost:8861/order/flow
不斷訪問:
六、流控規則
1、流量控制(iow conrol)
其原理是監控應用流量的QPS或并發線程數等指標,當達到指定的閾值時對流量進行控制,以避免被瞬時的流量高峰沖垮,從而保障應用的高可用性
==== FlowRule
RT(響應時間)1/0.2s =5
同一個資源可以創建多條限流規則。
Flcowlot會對該資源的所有限流規則依次遍歷,直到有規則觸發限流或者所有規則遍歷完畢。
一條限流規叫主要由下面幾個因素組成,我可以組合這些元素來實現不同的限流效果。
2、QPS
進入簇點鏈路選擇具體的訪問的API,然后點擊流控按鈕
QPS (Query Per Second):每秒請求數,就是說服務器在一秒的時間內處理了多少個請求。
訪問:http://localhost:8861/order/flow
一秒內多次刷新頁面
被限流了
自定義返回的流控信息
@GetMapping("/flow")@SentinelResource(value = "flow",blockHandler = "flowBlockHandler")public String flow(){return "正常訪問";}public String flowBlockHandler(BlockException exception){return "流控";}
重新啟動服務
我們再次訪問:http://localhost:8861/order/flow
我們發現我們如何訪問流控都不生效
因為流控沒有持久化,后期會說明持久化相關內容,現在就這樣
多次訪問:http://localhost:8861/order/flow
3、并發線程數
并發數控制用于保護業務線程池不被慢調用耗盡。
例如,當應用所依賴的下游應用由于某種原因導致服務不穩定、響應延遲增加,對于調用者來說,意味著吞吐量下降和更多的線程數占用,極端情況下甚至導致線程池耗盡。
為應對太多線程占用的情況,業內有使用隔離的方案,比如通過不同業務邏輯使用不同線程池來隔離業務自身之間的資源爭搶(線程池隔離)。
這種隔離方案雖然隔離性比較好,但是代價就是線程數目太多,線程上下文切換的 overhead 比較大,特別是對低延時的調用有比較大的影響。
Sentihel并發控制不負責創建和管理線程池,而是簡單統計當前請求上下文的線程數目(正在執行的調用數目),如果超出閾值,新的請求會被立即拒絕,效果類似于信號量隔離。
并發數控制通常在調用端進行配置。
可以利用jmeter測試
設置接口睡眠
@GetMapping("/flowThread")@SentinelResource(value = "flowThread",blockHandler = "flowBlockHandler")public String flowThread() throws InterruptedException{TimeUnit.SECONDS.sleep(5);return "正常訪問";}
訪問:http://localhost:8861/order/flowThread
多次訪問以后觸發流控
開啟兩個瀏覽器
4、BlockException異常統一處理
spigwebomvo接口資源限流入口在Handlerinterceptor的實現類AbstractSentiellterceptor的preHandle方法中,對異常的處理是BlockExceptionHandler的實現類
sentinel 1.7.1 引入了sentinel-spring-webmvc-adapter.jar
自定義BlockExceptionHandler的實現類統─處理BlockException
@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {@Overridepublic void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {// getRule() 資源 規則的詳細詳細System.out.println("BlockExceptionHandler BlockException===日日日日日日日日日日===" + e.getRule());String r = "";if (e instanceof FlowException) {System.out.println(100+"接口限流了");r = 100+"接口限流了";} else if (e instanceof DegradeException) {System.out.println(101+"服務降級了");r = 101+"服務降級了";} else if (e instanceof ParamFlowException) {System.out.println(102+"熱點參數限流了");r = 102+"熱點參數限流了";} else if (e instanceof SystemBlockException) {System.out.println(103+"觸發系統保護規則了");r = 103+"觸發系統保護規則了";} else if (e instanceof AuthorityException) {System.out.println(104+"授權規則不通過");r = 104+"授權規則不通過";}httpServletResponse.setStatus(500);httpServletResponse.setCharacterEncoding("utf-8");httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);new ObjectMapper().writeValue(httpServletResponse.getWriter(),r);}
}
修改一下之前的接口
@GetMapping("/flow")@SentinelResource(value = "flow",blockHandler = "flowBlockHandler")public String flow() throws InterruptedException{return "正常訪問";}
重新啟動運行
訪問:http://localhost:8861/order/flow
不斷訪問:http://localhost:8861/order/flow
七、流控模式
基于調用關系的流量控制。調用關系包括調用方、被調用方;
一個方法可能會調用其它方法,形成一個調用鏈路的層次關系。
直接資源調用達到設置的閾值后直接被流控拋出異常
1、直接
資源調用達到設置的閾值后直接被流控拋出異常
2、關聯
當兩個資源之間具有資源爭搶或者依賴關系的時候,這兩個資源便具有了關聯。比如對數據庫同一個字段的讀操作和寫操作存在爭搶,讀的速度過高會影響寫得速度,寫的速度過高會影響讀的速度。
如果放任讀寫操作爭搶資源,則爭搶本身帶來的開銷會降低整體的吞吐量。可使用關聯限流來避免具有關聯關系的資源之間過度的爭搶,舉例來說,read_db
和write_db
這兩個資源分別代表數據庫讀
寫,
我們可以給read_db設置限流規則來達到寫優先的目的:設置strategy
為faleConstant.STRSECY_BEATE
同時設置refResoure
為 write_db
。這樣當寫庫操作過于頻繁時,讀數據:杓請求會被限流。
例如為插入限流,影響查詢
編寫兩個接口
@RequestMapping("/addOrder")public String addOrder() throws InterruptedException{System.out.println("下單成功");return "下單成功";}@RequestMapping("/getOrder")public String getOrder() throws InterruptedException{System.out.println("查詢訂單");return "查詢訂單";}
重新運行項目
分別訪問:
http://localhost:8861/order/getOrder
http://localhost:8861/order/addOrder
生成訂單觸發查詢訂單
上述效果人工無法模擬,我們用 JMeter來模擬
下載:https://jmeter.apache.org/download_jmeter.cgi
下載解壓
雙擊如下
添加如下參數
正在不斷發起請求
我們訪問:http://localhost:8861/order/getOrder
發現被流控了
等待所有的請求都處理完
再次訪問:http://localhost:8861/order/getOrder
3、鏈路
更具調用鏈路入庫限流
下面中記錄了資源之間的調用鏈路,這些資源通過調用關系,相互之間構成一棵調用樹.
這棵樹的根節點是一個名字為getUser【方法】的虛擬節點,調用鏈的入口都是這個虛節點的子節點。
—棵典型的調用樹如下圖所示:
package com.itbluebox.order.service;public interface IOrderService {public String getUser();
}
package com.itbluebox.order.service;import org.springframework.stereotype.Service;@Service
public class OrderServiceImpl implements IOrderService{@Override@SentinelResource(value = "getUser")public String getUser() {return "張三";}
}
@Autowiredprivate IOrderService iOrderService;@RequestMapping("/test1")public String test1() throws InterruptedException{return iOrderService.getUser();}@RequestMapping("/test2")public String test2() throws InterruptedException{return iOrderService.getUser();}
分別訪問:
http://localhost:8861/order/test1
http://localhost:8861/order/test2
測試會發現鏈路規則不生效
注意,高版本此功能直接使用不生效,如何解決?
從1.6.3版本開始,Sentinel Web filter默認收斂所有URL的入口context,因此鏈路限流不生效1.7.0版本開始(對應SCA的2.1.1.RELEASE),官方在CommonFilter引入了
WEB CONTEXT_UNIFY參數,用于控制是否收斂context。將其配置為false即可根據不同的URL進行鏈路限流。SCA2.1.1.RELEASE之后的版本,可以通過配置
spring.cloud.sentinel.web-context-unify=false
即可關閉收斂我們當前使用的版本是SpringCloud Alibaba 2.1.0.RELEASE,無法實現鏈路限流。
目前官方還未發布SCA2.1.2.RELEASE,所以我們只能使用2.1.1.RELEASE,需要寫代碼的形式實現
web-context-unify: false #默認將調用鏈路收斂
重新設置流控規則
http://localhost:8861/order/test2
訪問:http://localhost:8861/order/test1
隨便怎么訪問都沒事
自定義流控返回的內容
@Service
public class OrderServiceImpl implements IOrderService{@Override@SentinelResource(value = "getUser",blockHandler = "blockHandlerGetUser")public String getUser() {return "張三";}public String blockHandlerGetUser(BlockException e){return "流控用戶";}}
重新啟動運行項目
重新設置流控規則
連續訪問:http://localhost:8861/order/test2
八、流控效果
快速失敗(RuleConstant.CONTROL_BEHAVIOR_WARM_UP
)方式是默認的流量控制方式,
當QPS超過任意規則的閾值后,新的請求就會被立即拒絕,拒絕方式為拋出Prlvrtcerntion。
這種方式適用于對系統處理能力確切已知的情況下,比如通過壓測確定了系統的準確水位時。
1、Warm Up(激增流量)預熱冷啟動
Warm Up (RuleConstant.CONTROL_BEHAVIOR_WARM_UP
)方式,即預熱冷啟動方式。
當系統長期處于低水位的情況下,當流量突然增加時,直接把系統拉升到高水位可能瞬間把系統壓
垮。
通過"冷啟動",讓通過的流量緩慢增加,在一定時間內逐漸增加到閾值上限,給冷系統一個預熱的時間,避免冷系統被壓垮。
冷加載因子: codeFactor默認是3,即請求QPS 從 threshold/3
開始,經預熱時長逐漸升至設定的QPS閾值。
通常冷啟動的過程系統允許通過的QPS曲線如下圖所示
將原有的限流規則去除掉
新建成功
訪問:http://localhost:8861/order/flow
不斷連續訪問
不斷點擊刷新,可以看到我們可以看到有 被拒絕有的通過了
2、均勻排隊(脈沖流量)
勻速排隊((‘RuileConstant.CONTROL_BEHAVIOR_RATE_LMITER
’)方式會嚴格控制請求通過的間隔時間,也即是讓請求以均勻的速度通過,對應的是漏桶算法。該方式的作用如下圖所示:
這種方式主要用于處理間隔性突發的流量,例如消息隊列。想象一下這樣的場景,在某一秒有大量的請求到來,而接下來的幾秒則處于空閑狀態,我們希望系統能夠在接下來的空閑期間逐漸處理這些請求,而不是在第一秒直接拒絕多余的請求。
注意:勻速排隊模式暫時不支持QPS > 1000的場景
先演示一下直接失敗的情況
上述實現功能,發起10次請求中間間隔5秒
等待運行結束
上述請求當中有間隔是空閑的,我們應該高效的利用起來這部分時間
通過均勻排隊(脈沖流量)來實現這一功能
我們發現所有的請求都執行成功了
九、降級規則
除了流量控制以外,對調用鏈路中不穩定的資源進行熔斷降級也是保障高可用的重要措施之一。
我們需要對不穩定的弱依賴服務調用進行熔斷降級,暫時切斷不穩定調用,避免局部不穩定因素導致整體的雪崩。
熔斷降級作為保護自身的手段,通常在客戶端(調用端)進行配置。
熔斷降級與隔離
熔斷降級規則說明
熔斷降級規則(DegradeRule)包含下面幾個重要的屬性:
1、熔斷策略:慢調用比例(LO_REOESLRATO):
選擇以慢調用比例作為閾值,需要設置允許的慢調用RT(即最大的響應時間),請求的響應時間大于該值則統計為慢調用。
當單位統計時長(statIntervalMs)內請求數目大于設置的最小請求數目,并且慢調用的比例大于閾值,則接下來的熔斷時長內請求會自動被熔斷。
經過熔斷時長后熔斷器會進入探測恢復狀態(HALF-OPEN狀態),若接下來的一個請求響應時間小于設置的慢調用RT則結束熔斷,若大于設置的慢調用RT則會再次被熔斷
修改源代碼將這里修改為降級
public String flowBlockHandler(BlockException exception){return "降級";}
創建成功
我們立馬訪問:http://localhost:8861/order/flowThread
接口被流控
10秒以后在訪問
2、熔斷策略:異常比例
創建新的接口
@RequestMapping("/err")public String err() throws InterruptedException{int i = 1/0;return "hello";}
重新啟動項目,訪問對應的接口
http://localhost:8861/order/err
我們可以看到服務第六次就被降級了
現在是半開狀態訪問異常后直接熔斷
3、熔斷策略:異常數
上面資源處于半開狀態這里需要重新啟動一下對應內容
訪問一下:http://localhost:8861/order/err
http://localhost:8861/order/err
連續訪問三次服務被熔斷