摘要:實(shí)現(xiàn)熔斷降級(jí)注解除了可以用來(lái)做限流控制之外,還能實(shí)現(xiàn)與類(lèi)似的熔斷降級(jí)策略。函數(shù)簽名要求返回值類(lèi)型必須與原函數(shù)返回值類(lèi)型一致方法參數(shù)列表需要為空,或者可以額外多一個(gè)類(lèi)型的參數(shù)用于接收對(duì)應(yīng)的異常。若未配置和,則被限流降級(jí)時(shí)會(huì)將直接拋出。
在之前的《使用Sentinel實(shí)現(xiàn)接口限流》一文中,我們僅依靠引入Spring Cloud Alibaba對(duì)Sentinel的整合封裝spring-cloud-starter-alibaba-sentinel,就完成了對(duì)所有Spring MVC接口的限流控制。然而,在實(shí)際應(yīng)用過(guò)程中,我們可能需要限流的層面不僅限于接口。可能對(duì)于某個(gè)方法的調(diào)用限流,對(duì)于某個(gè)外部資源的調(diào)用限流等都希望做到控制。呢么,這個(gè)時(shí)候我們就不得不手工定義需要限流的資源點(diǎn),并配置相關(guān)的限流策略等內(nèi)容了。
今天這篇我們就來(lái)一起學(xué)習(xí)一下,如何使用@SentinelResource注解靈活的定義控制資源以及如何配置控制策略。
自定義資源點(diǎn)下面的例子基于您已經(jīng)引入了Spring Cloud Alibaba Sentinel為基礎(chǔ),如果您還不會(huì)這些,建議優(yōu)先閱讀《使用Sentinel實(shí)現(xiàn)接口限流》。
第一步:在應(yīng)用主類(lèi)中增加注解支持的配置:
@SpringBootApplication public class TestApplication { public static void main(String[] args) { SpringApplication.run(TestApplication.class, args); } // 注解支持的配置Bean @Bean public SentinelResourceAspect sentinelResourceAspect() { return new SentinelResourceAspect(); } }
第二步:在需要通過(guò)Sentinel來(lái)控制流量的地方使用@SentinelResource注解,比如下面以控制Service邏輯層的某個(gè)方法為例:
@Slf4j @Service public class TestService { @SentinelResource(value = "doSomeThing") public void doSomeThing(String str) { log.info(str); } }
到這里一個(gè)需要被保護(hù)的方法就定義完成了。下面我們分別說(shuō)說(shuō),定義了資源點(diǎn)之后,我們?nèi)绾螌?shí)現(xiàn)不同的保護(hù)策略,包括:限流、降級(jí)等。
如何實(shí)現(xiàn)限流與熔斷降級(jí)在定義了資源點(diǎn)之后,我們就可以通過(guò)Dashboard來(lái)設(shè)置限流和降級(jí)策略來(lái)對(duì)資源點(diǎn)進(jìn)行保護(hù)了。同時(shí),也可以通過(guò)@SentinelResource來(lái)指定出現(xiàn)限流和降級(jí)時(shí)候的異常處理策略。下面,就來(lái)一起分別看看限流和降級(jí)都是如何實(shí)現(xiàn)的。
實(shí)現(xiàn)限流控制第一步:在Web層調(diào)用這個(gè)被保護(hù)的方法:
@RestController public class TestController { @Autowired private TestService testService; @GetMapping("/hello") public String hello() { estService.doSomeThing("hello " + new Date()); return "didispace.com"; } }
第二步:?jiǎn)?dòng)測(cè)試應(yīng)用,啟動(dòng)Sentinel-Dashboard。發(fā)一個(gè)請(qǐng)求到/hello接口上,使得Sentinel-Dashboard上可以看到如下圖所示的幾個(gè)控制點(diǎn):
可以看到,除了如之前入門(mén)實(shí)例中那樣有/hello資源點(diǎn)之外,多了一個(gè)doSomeThing資源點(diǎn)。可以通過(guò)界面為這個(gè)資源點(diǎn)設(shè)置限流規(guī)則,比如將其QPS設(shè)置為2。由于/hello資源不設(shè)置限流規(guī)則,所以只要請(qǐng)求/hello接口,就可以直接模擬調(diào)用doSomeThing資源,來(lái)觀察限流規(guī)則是否生效。
下面可以通過(guò)任何你喜歡的工具來(lái)調(diào)用/hello接口,只要QPS超過(guò)2,那么就會(huì)出現(xiàn)如下的錯(cuò)誤返回,代表限流策略生效了。
此時(shí),服務(wù)端的控制臺(tái)也會(huì)有對(duì)應(yīng)的限流報(bào)錯(cuò)日志:
2019-06-27 11:30:43.514 INFO 36898 --- [nio-8001-exec-3] c.d.a.sentinel.service.TestService : aaa 2019-06-27 11:30:43.905 ERROR 36898 --- [nio-8001-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.reflect.UndeclaredThrowableException] with root cause com.alibaba.csp.sentinel.slots.block.flow.FlowException: null實(shí)現(xiàn)限流的異常處理
默認(rèn)情況下,Sentinel對(duì)控制資源的限流處理是直接拋出異常,也就是上一節(jié)中貼出的日志內(nèi)容。在沒(méi)有合理的業(yè)務(wù)承接或者前端對(duì)接情況下可以這樣,但是正常情況為了更好的用戶業(yè)務(wù),都會(huì)實(shí)現(xiàn)一些被限流之后的特殊處理,我們不希望展示一個(gè)生硬的報(bào)錯(cuò)。那么只需要基于上面的例子做一些加工,比如:
@Slf4j @Service public class TestService { @SentinelResource(value = "doSomeThing", blockHandler = "exceptionHandler") public void doSomeThing(String str) { log.info(str); } // 限流與阻塞處理 public void exceptionHandler(String str, BlockException ex) { log.error( "blockHandler:" + str, ex); } }
主要做了兩件事:
通過(guò)@SentinelResource注解的blockHandler屬性制定具體的處理函數(shù)
實(shí)現(xiàn)處理函數(shù),該函數(shù)的傳參必須與資源點(diǎn)的傳參一樣,并且最后加上BlockException異常參數(shù);同時(shí),返回類(lèi)型也必須一樣。
如果熟悉Hystrix的讀者應(yīng)該會(huì)發(fā)現(xiàn),這樣的設(shè)計(jì)與HystrixCommand中定義fallback很相似,還是很容易理解的。
完成上面的改動(dòng)之后,再?lài)L試訪問(wèn)接口(注意限流規(guī)則需要配置好),此時(shí)前端就不會(huì)返回異常信息了,后端會(huì)打印exceptionHandler中定義的日志輸出。而在實(shí)際應(yīng)用的時(shí)候,只要根據(jù)業(yè)務(wù)需要對(duì)限流請(qǐng)求做緩存或者前端提示等都可以基于此方法來(lái)實(shí)現(xiàn)。
實(shí)現(xiàn)熔斷降級(jí)@SentinelResource注解除了可以用來(lái)做限流控制之外,還能實(shí)現(xiàn)與Hystrix類(lèi)似的熔斷降級(jí)策略。下面就來(lái)具體看看如何使用吧。
第一步:與限流控制一樣,使用@SentinelResource注解標(biāo)記資源點(diǎn),比如:
@Slf4j @Service public class TestService { @SentinelResource(value = "doSomeThing2") public void doSomeThing2(String str) { log.info(str); throw new RuntimeException("發(fā)生異常"); } }
這里在TestService類(lèi)中創(chuàng)建了一個(gè)新的方法,并使用@SentinelResource將該資源命名為doSomeThing2。該方法會(huì)拋出異常,以配合后續(xù)制定基于異常比例的降級(jí)策略(類(lèi)似Hystrix)。Sentinel相比Hystrix更豐富,還有基于響應(yīng)時(shí)間和異常數(shù)的降級(jí)策略。
第二步:在Web層調(diào)用這個(gè)被保護(hù)的方法:
@RestController public class TestController { @Autowired private TestService testService; @GetMapping("/hello2") public String hello2() { testService.doSomeThing2("hello2 " + new Date()); return "didispace.com"; } }
第三步:?jiǎn)?dòng)測(cè)試應(yīng)用,啟動(dòng)Sentinel-Dashboard。發(fā)一個(gè)請(qǐng)求到/hello2接口上,使得Sentinel-Dashboard上可以看到名為doSomeThing2的資源點(diǎn)。然后點(diǎn)擊”降級(jí)“按鈕,為該資源設(shè)置降級(jí)規(guī)則。這里使用異常比例策略,比例設(shè)置為0.5(即:50%的異常率),時(shí)間窗口設(shè)置為2(秒)。
第四步:驗(yàn)證熔斷降級(jí),根據(jù)上面的降級(jí)策略配置,當(dāng)doSomeThing2方法的調(diào)用QPS >= 5,如果異常率超過(guò)50%,那么后續(xù)2秒內(nèi)的調(diào)用將直接出發(fā)熔斷降級(jí),默認(rèn)情況會(huì)直接拋出DegradeException異常,比如:
2019-06-27 17:49:58.913 ERROR 99863 --- [nio-8001-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.reflect.UndeclaredThrowableException] with root cause com.alibaba.csp.sentinel.slots.block.degrade.DegradeException: null熔斷的降級(jí)處理
在Sentinel中定義熔斷的降級(jí)處理方法非常簡(jiǎn)單,與Hystrix非常相似。只需要使用@SentinelResource注解的fallback屬性來(lái)指定具體的方法名即可。這里也需要注意傳參與返回必須一致。比如:
@Slf4j @Service public class TestService { // 熔斷與降級(jí)處理 @SentinelResource(value = "doSomeThing2", fallback = "fallbackHandler") public void doSomeThing2(String str) { log.info(str); throw new RuntimeException("發(fā)生異常"); } public void fallbackHandler(String str) { log.error("fallbackHandler:" + str); } }
完成上面的改造之后,重啟應(yīng)用,并設(shè)置doSomeThing2資源的熔斷降級(jí)策略(使用異常百分比),然后頻繁的請(qǐng)求/hello2接口。在QPS>=5之后,由于這個(gè)接口一直在拋出異常,所以一定會(huì)滿足熔斷降級(jí)條件,這時(shí)候就會(huì)執(zhí)行fallbackHandler方法,不斷的打印如下日志:
2019-06-27 23:44:19.432 ERROR 58471 --- [nio-8001-exec-1] c.d.a.sentinel.service.TestService : fallbackHandler:hello2 Thu Jun 27 23:44:19 CST 2019 2019-06-27 23:44:19.599 ERROR 58471 --- [nio-8001-exec-2] c.d.a.sentinel.service.TestService : fallbackHandler:hello2 Thu Jun 27 23:44:19 CST 2019 2019-06-27 23:44:19.791 ERROR 58471 --- [nio-8001-exec-3] c.d.a.sentinel.service.TestService : fallbackHandler:hello2 Thu Jun 27 23:44:19 CST 2019 2019-06-27 23:44:19.975 ERROR 58471 --- [nio-8001-exec-4] c.d.a.sentinel.service.TestService : fallbackHandler:hello2 Thu Jun 27 23:44:19 CST 2019 2019-06-27 23:44:20.168 ERROR 58471 --- [nio-8001-exec-5] c.d.a.sentinel.service.TestService : fallbackHandler:hello2 Thu Jun 27 23:44:20 CST 2019更多注解屬性說(shuō)明
關(guān)于@SentinelResource注解最主要的兩個(gè)用法:限流控制和熔斷降級(jí)的具體使用案例介紹完了。另外,該注解還有一些其他更精細(xì)化的配置,比如忽略某些異常的配置、默認(rèn)降級(jí)函數(shù)等等,具體可見(jiàn)如下說(shuō)明:
value:資源名稱(chēng),必需項(xiàng)(不能為空)
entryType:entry 類(lèi)型,可選項(xiàng)(默認(rèn)為 EntryType.OUT)
blockHandler / blockHandlerClass: blockHandler 對(duì)應(yīng)處理 BlockException 的函數(shù)名稱(chēng),可選項(xiàng)。blockHandler 函數(shù)訪問(wèn)范圍需要是 public,返回類(lèi)型需要與原方法相匹配,參數(shù)類(lèi)型需要和原方法相匹配并且最后加一個(gè)額外的參數(shù),類(lèi)型為 BlockException。blockHandler 函數(shù)默認(rèn)需要和原方法在同一個(gè)類(lèi)中。若希望使用其他類(lèi)的函數(shù),則可以指定 blockHandlerClass 為對(duì)應(yīng)的類(lèi)的 Class 對(duì)象,注意對(duì)應(yīng)的函數(shù)必需為 static 函數(shù),否則無(wú)法解析。
fallback:fallback 函數(shù)名稱(chēng),可選項(xiàng),用于在拋出異常的時(shí)候提供 fallback 處理邏輯。fallback 函數(shù)可以針對(duì)所有類(lèi)型的異常(除了exceptionsToIgnore里面排除掉的異常類(lèi)型)進(jìn)行處理。fallback 函數(shù)簽名和位置要求:
返回值類(lèi)型必須與原函數(shù)返回值類(lèi)型一致;
方法參數(shù)列表需要和原函數(shù)一致,或者可以額外多一個(gè) Throwable 類(lèi)型的參數(shù)用于接收對(duì)應(yīng)的異常。
fallback 函數(shù)默認(rèn)需要和原方法在同一個(gè)類(lèi)中。若希望使用其他類(lèi)的函數(shù),則可以指定 fallbackClass 為對(duì)應(yīng)的類(lèi)的 Class 對(duì)象,注意對(duì)應(yīng)的函數(shù)必需為 static 函數(shù),否則無(wú)法解析。
defaultFallback(since 1.6.0):默認(rèn)的 fallback 函數(shù)名稱(chēng),可選項(xiàng),通常用于通用的 fallback 邏輯(即可以用于很多服務(wù)或方法)。默認(rèn) fallback 函數(shù)可以針對(duì)所有類(lèi)型的異常(除了exceptionsToIgnore里面排除掉的異常類(lèi)型)進(jìn)行處理。若同時(shí)配置了 fallback 和 defaultFallback,則只有 fallback 會(huì)生效。defaultFallback 函數(shù)簽名要求:
返回值類(lèi)型必須與原函數(shù)返回值類(lèi)型一致;
方法參數(shù)列表需要為空,或者可以額外多一個(gè) Throwable 類(lèi)型的參數(shù)用于接收對(duì)應(yīng)的異常。
defaultFallback 函數(shù)默認(rèn)需要和原方法在同一個(gè)類(lèi)中。若希望使用其他類(lèi)的函數(shù),則可以指定 fallbackClass 為對(duì)應(yīng)的類(lèi)的 Class 對(duì)象,注意對(duì)應(yīng)的函數(shù)必需為 static 函數(shù),否則無(wú)法解析。
exceptionsToIgnore(since 1.6.0):用于指定哪些異常被排除掉,不會(huì)計(jì)入異常統(tǒng)計(jì)中,也不會(huì)進(jìn)入 fallback 邏輯中,而是會(huì)原樣拋出。
注:1.6.0 之前的版本 fallback 函數(shù)只針對(duì)降級(jí)異常(DegradeException)進(jìn)行處理,不能針對(duì)業(yè)務(wù)異常進(jìn)行處理。
特別地,若 blockHandler 和 fallback 都進(jìn)行了配置,則被限流降級(jí)而拋出 BlockException 時(shí)只會(huì)進(jìn)入 blockHandler 處理邏輯。若未配置 blockHandler、fallback 和 defaultFallback,則被限流降級(jí)時(shí)會(huì)將 BlockException 直接拋出。
參考資料:Sentinel官方文檔代碼示例版本說(shuō)明:本文基于spring-cloud-alibaba-dependencies版本為0.2.2,如您遇到特殊問(wèn)題,請(qǐng)先核對(duì)版本是否一致,或直接參考代碼示例核對(duì)具體案例。
本文介紹內(nèi)容的客戶端代碼,示例讀者可以通過(guò)查看下面?zhèn)}庫(kù)中的alibaba-sentinel-annotation項(xiàng)目:
Github:https://github.com/dyc87112/SpringCloud-Learning/
Gitee:https://gitee.com/didispace/SpringCloud-Learning/
如果您對(duì)這些感興趣,歡迎star、follow、收藏、轉(zhuǎn)發(fā)給予支持!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/75109.html
摘要:現(xiàn)狀分布式場(chǎng)景中。因此要對(duì)在原服務(wù)不可用時(shí)進(jìn)行熔斷降級(jí)處理。分析熔斷降級(jí)可以服務(wù)端限流網(wǎng)關(guān)限流客戶端限流。它提供兩種資源隔離的模式信號(hào)量隔離和線程池隔離。支持流控熔斷降級(jí)系統(tǒng)保護(hù)等。它支持并發(fā)數(shù)的流量控制也支持熔斷降級(jí)。 現(xiàn)狀 分布式場(chǎng)景中。若服務(wù)不穩(wěn)定,會(huì)導(dǎo)致調(diào)用方服務(wù)也不可用,從而造成雪崩效應(yīng)。因此要對(duì)在原服務(wù)不可用時(shí)進(jìn)行熔斷降級(jí)處理。 分析 熔斷降級(jí)可以服務(wù)端限流、網(wǎng)關(guān)限流、客戶...
摘要:開(kāi)發(fā)階段很有意義。源碼整合配置文件中添加來(lái)開(kāi)啟編寫(xiě)類(lèi),實(shí)現(xiàn)默認(rèn)用戶遠(yuǎn)程調(diào)用被限流降級(jí),默認(rèn)用戶應(yīng)用定義可以拿到異常信息無(wú)法拿到異常信息若初啟動(dòng)應(yīng)用,設(shè)置流控規(guī)則,結(jié)果展示如下默認(rèn)用戶源碼 Sentinel API Github : WIKI Sphu (指明要保護(hù)的資源名稱(chēng)) Tracer (指明調(diào)用來(lái)源,異常統(tǒng)計(jì)接口) ContextUtil(標(biāo)示進(jìn)入調(diào)用鏈入口) 流控規(guī)則(針...
摘要:要使用注解來(lái)保護(hù)資源需要引入下面的依賴(lài)引入之后我們需要配置切面讓其生效,因?yàn)槭峭ㄟ^(guò)切面來(lái)實(shí)現(xiàn)的,我這邊以中使用進(jìn)行配置示列然后在需要限制的方法上加注解即可錯(cuò)誤發(fā)生在表示資源名,必填項(xiàng)處理的方法名,可選項(xiàng)。 在前面我們對(duì)Sentinel做了一個(gè)詳細(xì)的介紹,可以手動(dòng)的通過(guò)Sentinel提供的SphU類(lèi)來(lái)保護(hù)資源。這種做法不好的地方在于每個(gè)需要限制的地方都得寫(xiě)代碼,從 0.1.1 版本開(kāi)始...
摘要:介紹隨著微服務(wù)的流行,服務(wù)和服務(wù)之間的穩(wěn)定性變得越來(lái)越重要。以流量為切入點(diǎn),從流量控制熔斷降級(jí)系統(tǒng)負(fù)載保護(hù)等多個(gè)維度保護(hù)服務(wù)的穩(wěn)定性。完備的實(shí)時(shí)監(jiān)控同時(shí)提供實(shí)時(shí)的監(jiān)控功能。您只需要引入相應(yīng)的依賴(lài)并進(jìn)行簡(jiǎn)單的配置即可快速地接入。 Sentinel 介紹 隨著微服務(wù)的流行,服務(wù)和服務(wù)之間的穩(wěn)定性變得越來(lái)越重要。 Sentinel 以流量為切入點(diǎn),從流量控制、熔斷降級(jí)、系統(tǒng)負(fù)載保護(hù)等多個(gè)維度...
摘要:常見(jiàn)的降級(jí)方案表現(xiàn)形式無(wú)非以下三種類(lèi)型。的級(jí)別最低最先可以被降級(jí)掉。一旦當(dāng)系統(tǒng)壓力過(guò)大的時(shí)候,先把級(jí)別的功能降級(jí)掉。降級(jí)實(shí)現(xiàn)首先要制定觸發(fā)機(jī)制。將耗時(shí)的數(shù)據(jù)落盤(pán)操作降級(jí)為異步進(jìn)行。 如果這是第二次看到我的文章,歡迎掃描文末二維碼訂閱我喲~本文長(zhǎng)度為4069字,建議閱讀11分鐘。 也許你對(duì)降級(jí)已經(jīng)有了一些認(rèn)識(shí),認(rèn)真看完,我想這篇文章可能會(huì)給你帶來(lái)一些新的收獲~ 前面兩篇我們已經(jīng)聊過(guò)了「熔...
閱讀 1213·2021-11-25 09:43
閱讀 1968·2021-11-11 10:58
閱讀 1186·2021-11-08 13:18
閱讀 2657·2019-08-29 16:25
閱讀 3508·2019-08-29 12:51
閱讀 3306·2019-08-29 12:30
閱讀 747·2019-08-26 13:24
閱讀 3682·2019-08-26 10:38