一個(gè)基于 Dubbo 的微服務(wù)改造實(shí)踐

微服務(wù)的理論已經(jīng)夠多迟蜜,今天不妨看一個(gè)實(shí)戰(zhàn)案例涎拉。

寫在前面

基于微服務(wù)或者 SOA 的自動(dòng)化測(cè)試系統(tǒng)每個(gè)公司都有自己的特有的晾咪,我今天就主要介紹一下涎才,我們研發(fā)的一套 mock 測(cè)試系統(tǒng)鞋既。

目前面臨的問題

1、測(cè)試人員面臨的測(cè)試問題

我公司目前用的是基于 Dubbo 的微服務(wù)改造耍铜,服務(wù)之間的調(diào)用鏈路冗長邑闺,每個(gè)服務(wù)又是單獨(dú)的團(tuán)隊(duì)在維護(hù),每個(gè)團(tuán)隊(duì)又在不斷的演進(jìn)和維護(hù)各個(gè)服務(wù)棕兼,那么對(duì)測(cè)試人員將是非常大的挑戰(zhàn)陡舅。

測(cè)試人員每次進(jìn)行功能測(cè)試的時(shí)候,測(cè)試用例每次都需要重新寫一遍伴挚,無法將測(cè)試用例的數(shù)據(jù)沉淀靶衍,尤其是做自動(dòng)化測(cè)試的時(shí)候,測(cè)試人員準(zhǔn)備測(cè)試數(shù)據(jù)就需要很長時(shí)間茎芋,效率非常低颅眶。

目前接口自動(dòng)化測(cè)試框架也多種多樣,testng田弥,junit涛酗,F(xiàn)itnesse 等,但都需要測(cè)試人員具備測(cè)試代碼編寫能力,如果要做好和手工接口測(cè)試一樣效果的自動(dòng)化測(cè)試更是需要大量的代碼堆積煤杀,后期維護(hù)代碼成本非常大眷蜈。因此做成簡單配置用例流,無需編寫測(cè)試代碼的系統(tǒng)是更貼合實(shí)際工作要求沈自。

舉個(gè)例子:拿互聯(lián)網(wǎng)支付系統(tǒng)來說酌儒,某個(gè)團(tuán)隊(duì)新增了支付交易的需求,這時(shí)候要進(jìn)行測(cè)試枯途,測(cè)試人員除了要測(cè)試支付交易需求本身是否正確,同時(shí)也要結(jié)合上下游的服務(wù)整體進(jìn)行回歸測(cè)試酪夷,這時(shí)候開發(fā)人員往往在支付交易系統(tǒng)中采用“硬編碼”的方式對(duì)上下游的系統(tǒng)進(jìn)行“擋板”鸥印,如果測(cè)試人員對(duì)測(cè)試數(shù)據(jù)有所調(diào)整那么“擋板”也要跟著調(diào)整字管,同時(shí)在項(xiàng)目正式上線的時(shí)候歇由,如果開發(fā)人員沒有將“擋板”程序去除干凈萝衩,將面臨嚴(yán)重的線上問題喜滨。

2验游、測(cè)試人員如何驗(yàn)證數(shù)據(jù)

接口返回值

通過肉眼分析比對(duì)接口返回值的內(nèi)容旅挤,判斷業(yè)務(wù)邏輯正確性。

數(shù)據(jù)庫驗(yàn)證

測(cè)試接口的輸入值需要通過手工編寫數(shù)據(jù)庫 SQL 查詢獲取,接口調(diào)用完成后乙埃,需要通過大量的 SQL 驗(yàn)證數(shù)據(jù)庫值的正確性。

日志驗(yàn)證

通過返回值和數(shù)據(jù)庫不能確保代碼走到了預(yù)期的邏輯,只能通過肉眼觀察日志確認(rèn)代碼的實(shí)際運(yùn)行邏輯

測(cè)試報(bào)告

人工記錄用例結(jié)果赃阀,人工編寫報(bào)告,耗時(shí)耗力仓技,難以準(zhǔn)確定位代碼問題

Mock 模擬系統(tǒng)的產(chǎn)生

業(yè)務(wù)系統(tǒng)調(diào)用眾多其他系統(tǒng)完成功能邏輯兆衅,而想要得到其他系統(tǒng)接口的特定輸出地沮,需要做相應(yīng)的運(yùn)營配置嗜浮,增加很多的溝通成本;甚至偶發(fā)性 bug 只能在特定的環(huán)境狀況下復(fù)現(xiàn)摩疑,只能作為不可測(cè)的邏輯危融。

以風(fēng)控系統(tǒng)為例,如果業(yè)務(wù)系統(tǒng)需要測(cè)試某個(gè)商編某個(gè)商品類別下的累積限額雷袋,需要風(fēng)控的同事配合不斷修改限額閾值吉殃,目前的情況是多個(gè)業(yè)務(wù)系統(tǒng)都在接入風(fēng)控,配合測(cè)試的人力成本和時(shí)間成本是很高的楷怒。為此設(shè)計(jì)了擋板模擬系統(tǒng)蛋勺,其功能結(jié)構(gòu)如下:

針對(duì)測(cè)試人員測(cè)試用例數(shù)據(jù)無法沉淀和復(fù)用的問題,我們將采用“用例與日志錨點(diǎn)庫”方案:

用例庫的建立可以實(shí)現(xiàn)對(duì)以往測(cè)試規(guī)則的記錄與復(fù)用鸠删,改變每次回歸測(cè)試都要重復(fù)編寫用例與準(zhǔn)備數(shù)據(jù)的現(xiàn)狀抱完。

日志錨點(diǎn)庫是對(duì)代碼執(zhí)行流程的有效驗(yàn)證,除了可以應(yīng)用在測(cè)試環(huán)境中刃泡,還可基于大數(shù)據(jù)日志中心對(duì)生產(chǎn)代碼的運(yùn)行做日常監(jiān)控乾蛤。

交易與支付系統(tǒng)業(yè)務(wù)邏輯復(fù)雜,靠人腦和文檔記憶功能關(guān)系難免疏漏捅僵,而用例庫和日志錨點(diǎn)庫會(huì)隨著業(yè)務(wù)的變更測(cè)試而隨即維護(hù)家卖,是一部活文檔。

Mock 系統(tǒng)的技術(shù)方案

1庙楚、系統(tǒng)的功能點(diǎn)

說明: 上圖羅列了整個(gè) Mock 測(cè)試系統(tǒng)的功能點(diǎn)有哪些上荡,共分為:配置接口數(shù)據(jù)、創(chuàng)建測(cè)試用例馒闷、創(chuàng)建測(cè)試集酪捡、創(chuàng)建測(cè)試計(jì)劃、執(zhí)行測(cè)試計(jì)劃以及生成測(cè)試報(bào)告等大功能纳账。

配置接口數(shù)據(jù)界面圖

創(chuàng)建測(cè)試用例配置圖

擋板請(qǐng)求路由配置圖

測(cè)試執(zhí)行結(jié)果

2逛薇、系統(tǒng)的功能流程圖

說明:依據(jù)上下文環(huán)境,利用工廠類動(dòng)態(tài)注入 spring 對(duì)遠(yuǎn)程接口的依賴疏虫,保持線上與測(cè)試的代碼一致永罚。在測(cè)試環(huán)境中,通過 mock 系統(tǒng)管理端卧秘,可以隨時(shí)調(diào)整請(qǐng)求的流向呢袱,“指哪打哪”。

說明:執(zhí)行某項(xiàng)測(cè)試用例翅敌, 利用 mock 將被測(cè)試接口與底層依賴接口隔離開來羞福,可以方便的模擬數(shù)據(jù),并監(jiān)控輸入輸出蚯涮。用例執(zhí)行完畢后治专,使用返回?cái)嘌月袅辍QL 查詢、日志標(biāo)記等多種手段驗(yàn)證张峰。

Dubbo 的 Mock 功能

1泪蔫、Dubbo 的 Mock 使用

Dubbo 自帶的 Mock 功能首先是為了做服務(wù)降級(jí),比如某驗(yàn)權(quán)服務(wù)挟炬,當(dāng)服務(wù)提供方全部掛掉后,客戶端不拋出異常嗦哆,而是通過 Mock 數(shù)據(jù)返回授權(quán)失敗谤祖。

我們從官網(wǎng)上舉一個(gè)例子來說明:

我們可以在期望的 reference 標(biāo)簽上加一個(gè) mock="force",就可以將當(dāng)前服務(wù)設(shè)置為 mock老速。但是設(shè)置完 mock 屬性后還沒有結(jié)束粥喜,需要有一個(gè) Mock 類對(duì)應(yīng)我們的服務(wù)接口類。

規(guī)則如下:

接口名 + Mock 后綴橘券,服務(wù)接口調(diào)用失敗 Mock 實(shí)現(xiàn)類额湘,該 Mock 類必須有一個(gè)無參構(gòu)造函數(shù)。

對(duì)應(yīng)到 com.foo.BarService 的話旁舰,則創(chuàng)建 BarServiceMock 類锋华。

經(jīng)過以上設(shè)置后,當(dāng)調(diào)用 BarService 進(jìn)行遠(yuǎn)程調(diào)用的話箭窜,直接請(qǐng)求到 BarServiceMock 類上面進(jìn)行模擬測(cè)試毯焕。

2、Dubbo Mock 的原理解析

在 dubbo 的配置文件中

可以看到如下配置列表:

我們可以看到配置文件中實(shí)際上有五大路由策略:

AvailableCluster: 獲取可用的調(diào)用磺樱。遍歷所有 Invokers 判斷 Invoker.isAvalible, 只要一個(gè)有為 true 直接調(diào)用返回纳猫,不管成不成功。

BroadcastCluster: 廣播調(diào)用竹捉。遍歷所有 Invokers, 逐個(gè)調(diào)用每個(gè)調(diào)用 catch 住異常不影響其他 invoker 調(diào)用芜辕。

FailbackCluster: 失敗自動(dòng)恢復(fù), 對(duì)于 invoker 調(diào)用失敗块差, 后臺(tái)記錄失敗請(qǐng)求侵续,任務(wù)定時(shí)重發(fā), 通常用于通知。

FailfastCluster: 快速失敗憨闰,只發(fā)起一次調(diào)用询兴,失敗立即保錯(cuò),通常用于非冪等性操作起趾。

FailoverCluster: 失敗轉(zhuǎn)移诗舰,當(dāng)出現(xiàn)失敗,重試其它服務(wù)器训裆,通常用于讀操作眶根,但重試會(huì)帶來更長延遲蜀铲。

Dubbo 中默認(rèn)使用的是 FailoverCluster 策略棒拂,而在實(shí)際執(zhí)行的過程中是 FailoverCluster 會(huì)被先被注入到 MockClusterWrapper 中钮孵,過程就是:

MockClusterWrapper 內(nèi)部會(huì)創(chuàng)建一個(gè) MockClusterInvoker 對(duì)象。實(shí)際創(chuàng)建是封裝了 FailoverClusterInvoker 的 MockClusterInvoker吕粹,這樣就成功地在 Invoker 之中植入了 Mock 機(jī)制族扰。

我們來看 MockClusterInvoker 的內(nèi)部實(shí)現(xiàn):

如果在沒有配置之中沒有設(shè)置 mock厌丑,那么直接把方法調(diào)用轉(zhuǎn)發(fā)給實(shí)際的 Invoker(也就是 FailoverClusterInvoker)。

如果配置了強(qiáng)制執(zhí)行 Mock渔呵,比如發(fā)生服務(wù)降級(jí)怒竿,那么直接按照配置執(zhí)行 mock 之后返回。

如果是其它的情況扩氢,比如只是配置的是 mock=fail:return null耕驰,那么就是在正常的調(diào)用出現(xiàn)異常的時(shí)候按照配置執(zhí)行 mock。

3录豺、Dubbo Mock 的適用場景

Dubbo 的 Mock 功能主要是為了做服務(wù)降級(jí)而使用的朦肘,服務(wù)提供方在客戶端執(zhí)行容錯(cuò)邏輯,在出現(xiàn) RpcException(比如網(wǎng)絡(luò)失敗双饥,超時(shí)等) 時(shí)進(jìn)行容錯(cuò)媒抠,然后執(zhí)行降級(jí) Mock 邏輯。自身并不適合做 Mock 測(cè)試系統(tǒng)咏花。

自動(dòng)化 Mock 系統(tǒng)的實(shí)現(xiàn)

1领舰、Mock 系統(tǒng)的簡單用例圖

2、Mock 系統(tǒng)的架構(gòu)圖

為了基于 Dubbo 實(shí)現(xiàn) Mock 功能迟螺,需要對(duì) Dubbo 源碼進(jìn)行一些必要的修改冲秽,通過上面的架構(gòu)圖我們可以看到,實(shí)際上我們正是利用了 Dubbo 的 Filter chain 過濾器鏈這一機(jī)制實(shí)現(xiàn)的矩父,為了方便大家更好的理解锉桑,下面將簡單介紹一下 Dubbo 的 Filter 機(jī)制。

?Dubbo 的 Filter 原理分析

Filter:是一種遞歸的鏈?zhǔn)秸{(diào)用窍株,用來在遠(yuǎn)程調(diào)用真正執(zhí)行的前后加入一些邏輯民轴,跟 aop 的攔截器 servlet 中 filter 概念一樣的。

Filter 接口定義:

Filter 的實(shí)現(xiàn)類需要打上 @Activate 注解, @Activate 的 group 屬性是個(gè) string 數(shù)組球订,我們可以通過這個(gè)屬性來指定這個(gè) filter 是在 consumer, provider 還是兩者情況下激活后裸,所謂激活就是能夠被獲取,組成 filter 鏈冒滩。

關(guān)于 SPI 的詳細(xì)介紹請(qǐng)大家參考我之前寫的另一篇文章:

http://www.reibang.com/p/46aa69643c97

ProtocolFilterWrapper:在服務(wù)的暴露與引用的過程中根據(jù) KEY 是 PROVIDER 還是 CONSUMER 來構(gòu)建服務(wù)提供者與消費(fèi)者的調(diào)用過濾器鏈微驶,F(xiàn)ilter 最終都要被封裝到 Wrapper 中的。

構(gòu)建 filter 鏈,當(dāng)我們獲取激活的 filter 集合后就通過 ProtocolFilterWrapper 類中的 buildInvokerChain 方法來構(gòu)建因苹。

?Mock 流程介紹

注:我們?cè)谥行录恿俗远x的“env=test”這樣的屬性配置用來標(biāo)明當(dāng)前環(huán)境是測(cè)試的還是正式的苟耻,用戶每次通過 Dubbo 請(qǐng)求的遠(yuǎn)程服務(wù)的時(shí)候,都會(huì)首先經(jīng)過我們自定義的 Filter扶檐,我們自定義的 Filter 會(huì)首先判斷當(dāng)前的環(huán)境是 test 還是正式凶杖,如果是 test 的環(huán)境則直接訪問 Mock 配置中心獲取提前配置好的 Mock 數(shù)據(jù)并封裝成用戶定義的 Response 對(duì)象返回。

3款筑、Mock 系統(tǒng)的配置中心

Mock 配置中心就是用戶將 mock 數(shù)據(jù)與應(yīng)用環(huán)境建立關(guān)系的系統(tǒng)智蝠,整個(gè)系統(tǒng)就像一個(gè)工作流引擎:

環(huán)境設(shè)置 ->應(yīng)用名稱設(shè)置 ->擋板規(guī)則設(shè)置 ->Facade 服務(wù)接口設(shè)置 ->方法規(guī)則設(shè)置

環(huán)境設(shè)置

注:如果尚未映射來源 IP 地址到環(huán)境,則點(diǎn)擊環(huán)境列表導(dǎo)航鏈接奈梳,進(jìn)入環(huán)境列表頁面杈湾,點(diǎn)擊添加,輸入源 IP 及環(huán)境名颈嚼,點(diǎn)擊確定按鈕毛秘,實(shí)現(xiàn)源 IP 到所設(shè)環(huán)境的映射饭寺。每個(gè)用戶都可以建立屬于自己的測(cè)試環(huán)境阻课。

應(yīng)用名稱設(shè)置

注:創(chuàng)建所使用系統(tǒng)的應(yīng)用名稱,Mock 配置中心默認(rèn)使用中的名稱作為應(yīng)用名稱艰匙。

擋板規(guī)則

注:每一個(gè)擋板規(guī)則都是由一個(gè)環(huán)境名稱和應(yīng)用名稱組成的唯一擋板限煞,在擋板設(shè)置中選擇環(huán)境名稱和應(yīng)用名稱,并且設(shè)置擋板的有效狀態(tài)员凝。

Facade 規(guī)則

注:每一個(gè) Facade 就是一個(gè) Dubbo 的服務(wù)接口類署驻,在這里將自己的 Facade 名稱與全路徑與擋板名稱對(duì)應(yīng),以標(biāo)識(shí)哪些 Facade 服務(wù)接口類是屬于哪個(gè)擋板的健霹。

方法規(guī)則

注:方法規(guī)則是用來設(shè)置每個(gè) Facade 中的需要 mock 的方法的旺上,可以對(duì)不同的方法設(shè)置方法執(zhí)行時(shí)間、方法拋出的異常等等糖埋。

4宣吱、Mock 系統(tǒng)的其他功能

由于不少應(yīng)用項(xiàng)目開發(fā)完后想對(duì)其進(jìn)行單獨(dú)壓測(cè),而很多時(shí)候應(yīng)用系統(tǒng)和其他業(yè)務(wù)系統(tǒng)形成了依賴關(guān)系瞳别,如果不布署其他應(yīng)用系統(tǒng)則無法完成壓測(cè)征候,為了更好的支持性能測(cè)試組進(jìn)行擋板壓測(cè),Mock 系統(tǒng)支持壓測(cè)功能祟敛,而 Mock 系統(tǒng)自身也可以達(dá)到單臺(tái)服務(wù)器 1000TPS 以上(8C8G)疤坝。

歡迎工作一到五年的Java工程師朋友們加入Java程序員開發(fā): 854393687

群內(nèi)提供免費(fèi)的Java架構(gòu)學(xué)習(xí)資料(里面有高可用、高并發(fā)馆铁、高性能及分布式跑揉、Jvm性能調(diào)優(yōu)、Spring源碼埠巨,MyBatis畔裕,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個(gè)知識(shí)點(diǎn)的架構(gòu)資料)合理利用自己每一分每一秒的時(shí)間來學(xué)習(xí)提升自己衣撬,不要再用"沒有時(shí)間“來掩飾自己思想上的懶惰!趁年輕扮饶,使勁拼具练,給未來的自己一個(gè)交代!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末甜无,一起剝皮案震驚了整個(gè)濱河市扛点,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌岂丘,老刑警劉巖陵究,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異奥帘,居然都是意外死亡铜邮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門寨蹋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來松蒜,“玉大人,你說我怎么就攤上這事已旧〗彰纾” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵运褪,是天一觀的道長惊楼。 經(jīng)常有香客問我,道長秸讹,這世上最難降的妖魔是什么檀咙? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮璃诀,結(jié)果婚禮上弧可,老公的妹妹穿的比我還像新娘。我一直安慰自己文虏,他們只是感情好侣诺,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著氧秘,像睡著了一般年鸳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上丸相,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天搔确,我揣著相機(jī)與錄音,去河邊找鬼。 笑死膳算,一個(gè)胖子當(dāng)著我的面吹牛座硕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播涕蜂,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼华匾,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了机隙?” 一聲冷哼從身側(cè)響起蜘拉,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎有鹿,沒想到半個(gè)月后旭旭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡葱跋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年持寄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片娱俺。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡稍味,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出矢否,到底是詐尸還是另有隱情仲闽,我是刑警寧澤脑溢,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布僵朗,位于F島的核電站,受9級(jí)特大地震影響屑彻,放射性物質(zhì)發(fā)生泄漏验庙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一社牲、第九天 我趴在偏房一處隱蔽的房頂上張望粪薛。 院中可真熱鬧,春花似錦搏恤、人聲如沸违寿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽藤巢。三九已至,卻和暖如春息罗,著一層夾襖步出監(jiān)牢的瞬間掂咒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留绍刮,地道東北人温圆。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像孩革,于是被迫代替她去往敵國和親岁歉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容