dubbo 服務(wù)降級(jí)
1.開(kāi)關(guān)
先講一下開(kāi)關(guān)的由來(lái),例如京東在6月18日做店慶促銷(xiāo)活動(dòng),在交易下單環(huán)節(jié),可能需要調(diào)用A、B、C三個(gè)接口來(lái)完成,但是其實(shí)A和B是必須的,C只是附加的功能(例如在下單的時(shí)候做一下推薦),可有可無(wú),在平時(shí)系統(tǒng)沒(méi)有壓力,容量充足的情況下,調(diào)用下沒(méi)問(wèn)題,但是在類(lèi)似店慶之類(lèi)的大促環(huán)節(jié),系統(tǒng)已經(jīng)滿(mǎn)負(fù)荷了,這時(shí)候其實(shí)完全可以不去調(diào)用C接口,怎么實(shí)現(xiàn)這個(gè)呢?改代碼?no,no,no,這樣太不敏捷,此時(shí)開(kāi)關(guān)誕生了,開(kāi)發(fā)人員只要簡(jiǎn)單執(zhí)行一下命令或者點(diǎn)一下頁(yè)面,就可以關(guān)掉對(duì)于C接口的調(diào)用,在大促過(guò)去之后,再把開(kāi)關(guān)恢復(fù)回去即可。
2.什么是服務(wù)降級(jí)
服務(wù)降級(jí),當(dāng)服務(wù)器壓力劇增的情況下,根據(jù)當(dāng)前業(yè)務(wù)情況及流量對(duì)一些服務(wù)和頁(yè)面有策略的降級(jí),以此釋放服務(wù)器資源以保證核心任務(wù)的正常運(yùn)行。
3.服務(wù)降級(jí)方式:
- 服務(wù)接口拒絕服務(wù):無(wú)用戶(hù)特定信息,頁(yè)面能訪問(wèn),但是添加刪除提示服務(wù)器繁忙。頁(yè)面內(nèi)容也可在Varnish或CDN內(nèi)獲取。
- 頁(yè)面拒絕服務(wù):頁(yè)面提示由于服務(wù)繁忙此服務(wù)暫停。跳轉(zhuǎn)到varnish或nginx的一個(gè)靜態(tài)頁(yè)面。
- 延遲持久化:頁(yè)面訪問(wèn)照常,但是涉及記錄變更,會(huì)提示稍晚能看到結(jié)果,將數(shù)據(jù)記錄到異步隊(duì)列或log,服務(wù)恢復(fù)后執(zhí)行。
- 隨機(jī)拒絕服務(wù):服務(wù)接口隨機(jī)拒絕服務(wù),讓用戶(hù)重試,目前較少有人采用。因?yàn)橛脩?hù)體驗(yàn)不佳。
經(jīng)過(guò)過(guò)12306搶票的人應(yīng)該經(jīng)常會(huì)遇到這個(gè)問(wèn)題:在搶票高峰的時(shí)候,明明票還有,但是查詢(xún)出來(lái)的列表卻是為空的(如果沒(méi)票列表也應(yīng)該會(huì)呈現(xiàn));等高峰過(guò)后再查詢(xún),列表又恢復(fù)正常。個(gè)人猜測(cè)應(yīng)該是查詢(xún)過(guò)程中出現(xiàn)了問(wèn)題,要么超時(shí),要么網(wǎng)絡(luò)問(wèn)題導(dǎo)致查詢(xún)失敗采用的服務(wù)降級(jí)處理。所以,最終呈現(xiàn)給用戶(hù)的并不是內(nèi)部系統(tǒng)出錯(cuò)之類(lèi)的提示,而是一個(gè)空的列表。好了,言歸正傳,在dubbo中想實(shí)現(xiàn)服務(wù)降級(jí),需要怎么樣做可以實(shí)現(xiàn)?
4 dubbo降級(jí)服務(wù)
dubbo開(kāi)發(fā)中,通常是微服務(wù)架構(gòu),那么在使用過(guò)程中可能會(huì)遇到多種問(wèn)題:
1)多個(gè)服務(wù)之間可能由于服務(wù)沒(méi)有啟動(dòng)或者網(wǎng)絡(luò)不通,調(diào)用中會(huì)出現(xiàn)遠(yuǎn)程調(diào)用失敗;
2) 服務(wù)請(qǐng)求過(guò)大,需要停止部分服務(wù)以保證核心業(yè)務(wù)的正常運(yùn)行;
以上兩個(gè)問(wèn)題可以使用Dubbo的服務(wù)降級(jí)來(lái)實(shí)現(xiàn);
即:在服務(wù)宕掉或者并發(fā)數(shù)太高導(dǎo)致的RpcException異常時(shí),進(jìn)行友好的處理或者提示,而不是內(nèi)部報(bào)錯(cuò)導(dǎo)致系統(tǒng)不可用。也停掉非核心調(diào)用,減輕服務(wù)器壓力
解決方法:
dubbo提供了mock配置,可以很好的實(shí)現(xiàn)dubbo服務(wù)降級(jí),
mock主要有兩種配置方式,
第1種
直接返回一個(gè)固定的字符串
具體配置:
在服務(wù)調(diào)用方配置mock參數(shù): 直接定義返回值
<dubbo:reference id="xxxService" interface="com.x..service.xxxxService" check="false" mock="return 123456..." />
說(shuō)明:配置了mock參數(shù)之后,假設(shè)在調(diào)用服務(wù)的時(shí)候,遠(yuǎn)程服務(wù)沒(méi)有啟動(dòng),或者各種網(wǎng)絡(luò)異常了,那遠(yuǎn)程服務(wù)會(huì)把這個(gè)mock配置的值返回,也就是會(huì)返回123456...
通過(guò)這種方式就可以避免了因?yàn)榉?wù)調(diào)用不了而出現(xiàn)異常錯(cuò)誤而帶來(lái)的程序不可用(起碼是有值返回的,然后可以根據(jù)值進(jìn)行業(yè)務(wù)邏輯處理判斷等等)。
注:除了配置mock參數(shù)之外,其它地方不用變。
第2種
根據(jù)自定義mock業(yè)務(wù)處理類(lèi)進(jìn)行返回 mock值設(shè)置為boolean 類(lèi)型
具體配置:
在服務(wù)調(diào)用方配置mock參數(shù):
<dubbo:reference id="xxxService" interface="com.x..service.xxxxService" check="false" mock="true" />
說(shuō)明:配置了mock參數(shù)之后,假設(shè)在調(diào)用服務(wù)的時(shí)候,遠(yuǎn)程服務(wù)沒(méi)有啟動(dòng),或者各種網(wǎng)絡(luò)異常了,那遠(yuǎn)程服務(wù)會(huì)去尋找自定義的mock業(yè)務(wù)處理類(lèi)進(jìn)行業(yè)務(wù)處理。
因此還需配置一個(gè)自定義mock業(yè)務(wù)處理類(lèi)
在接口服務(wù)xxxxService的目錄下創(chuàng)建相應(yīng)的mock業(yè)務(wù)處理類(lèi),同時(shí)實(shí)現(xiàn)業(yè)務(wù)接口xxxxService(),接口名要注意命名規(guī)范:接口名+Mock后綴,mock實(shí)現(xiàn)需要保證有無(wú)參的構(gòu)造方法。
//要實(shí)現(xiàn)接口,并實(shí)現(xiàn)相關(guān)方法
public class xxxxServiceMock implements xxxxService { //降級(jí)時(shí)用到 @Override public String getXXXX(int id) { return "this is exception 自定義...."; } }
配置完成后,此時(shí)如果調(diào)用失敗會(huì)調(diào)用自定義的Mock業(yè)務(wù)實(shí)現(xiàn)(即上面的實(shí)現(xiàn)類(lèi)中對(duì)應(yīng)方法 getXXXX)。
5 管理界面手動(dòng)配置
以上的配置其實(shí)除了在代碼中配置之外,還可以在dubb-adming管理界面直接手動(dòng)配置:

分別是屏蔽和容錯(cuò):
屏蔽:force.mock (即:屏蔽請(qǐng)求,直接返回某個(gè)值,如上面的字符串,mock="return 123456...");
容錯(cuò):fail.mock (即:允許請(qǐng)求,在請(qǐng)求失敗的時(shí)候,再返回某個(gè)值,如:mock="fail:return 123456...");
6、思考
通過(guò)例子可以知道,通過(guò)mock的配置,可以很好的實(shí)現(xiàn)dubbo服務(wù)降級(jí)。但是,比如例子里,接口IUser本身定義了兩個(gè)接口,一個(gè)是新增用戶(hù),一個(gè)是根據(jù)id查詢(xún)用戶(hù)信息。對(duì)于根據(jù)id查詢(xún)用戶(hù)信息,在調(diào)用失敗的時(shí)候返回null很好理解,可能是由于驗(yàn)證失敗或者記錄刪除了,但是對(duì)于新增用戶(hù),可能就需要拋出具體的業(yè)務(wù)信息,否則程序無(wú)法處理后續(xù)的業(yè)務(wù),包括頁(yè)面彈出”添加成功“或者列表刷新的時(shí)候無(wú)法查看到最新的記錄,這樣體驗(yàn)將會(huì)非常不好。所以,如果要有較好的區(qū)分,可以通過(guò)以下的方式,可以更好的實(shí)現(xiàn)降級(jí):
(1)將接口進(jìn)行歸類(lèi),查詢(xún)類(lèi)和變更操作類(lèi):對(duì)于查詢(xún)的分為一個(gè)接口類(lèi),變更的歸類(lèi)為其他的接口類(lèi),這樣對(duì)于查詢(xún)的可以使用mock="return null"進(jìn)行降級(jí)操作;對(duì)于變更類(lèi)的,可以仍舊使用try……catch進(jìn)行異常捕獲處理;
(2)配置mock="true",同時(shí)mock實(shí)現(xiàn)接口,接口名要注意命名規(guī)范:接口名+Mock后綴。此時(shí)如果調(diào)用失敗會(huì)調(diào)用Mock實(shí)現(xiàn)的方法。mock實(shí)現(xiàn)需要保證有無(wú)參的構(gòu)造方法。
posted on 2020-08-10 23:04 鑫男 閱讀(770) 評(píng)論(0) 收藏 舉報(bào)
浙公網(wǎng)安備 33010602011771號(hào)