1. 程式人生 > >一個基於 Dubbo 的微服務改造實踐

一個基於 Dubbo 的微服務改造實踐

微服務的理論已經夠多,今天不妨看一個實戰案例。

基於微服務或者 SOA 的自動化測試系統每個公司都有自己的特有的,我今天就主要介紹一下,我們研發的一套 mock 測試系統。

目前面臨的問題

1、測試人員面臨的測試問題

我公司目前用的是基於 Dubbo 的微服務改造,服務之間的呼叫鏈路冗長,每個服務又是單獨的團隊在維護,每個團隊又在不斷的演進和維護各個服務,那麼對測試人員將是非常大的挑戰。

測試人員每次進行功能測試的時候,測試用例每次都需要重新寫一遍,無法將測試用例的資料沉澱,尤其是做自動化測試的時候,測試人員準備測試資料就需要很長時間,效率非常低。

目前介面自動化測試框架也多種多樣,testng,junit,Fitnesse 等,但都需要測試人員具備測試程式碼編寫能力,如果要做好和手工介面測試一樣效果的自動化測試更是需要大量的程式碼堆積,後期維護程式碼成本非常大。因此做成簡單配置用例流,無需編寫測試程式碼的系統是更貼合實際工作要求。

舉個例子:拿網際網路支付系統來說,某個團隊新增了支付交易的需求,這時候要進行測試,測試人員除了要測試支付交易需求本身是否正確,同時也要結合上下游的服務整體進行迴歸測試,這時候開發人員往往在支付交易系統中採用“硬編碼”的方式對上下游的系統進行“擋板”,如果測試人員對測試資料有所調整那麼“擋板”也要跟著調整,同時在專案正式上線的時候,如果開發人員沒有將“擋板”程式去除乾淨,將面臨嚴重的線上問題。

2、測試人員如何驗證資料

介面返回值

通過肉眼分析比對介面返回值的內容,判斷業務邏輯正確性。

資料庫驗證

測試介面的輸入值需要通過手工編寫資料庫 SQL 查詢獲取,介面呼叫完成後,需要通過大量的 SQL 驗證資料庫值的正確性。

日誌驗證

通過返回值和資料庫不能確保程式碼走到了預期的邏輯,只能通過肉眼觀察日誌確認程式碼的實際執行邏輯

測試報告

人工記錄用例結果,人工編寫報告,耗時耗力,難以準確定位程式碼問題

Mock 模擬系統的產生

業務系統呼叫眾多其他系統完成功能邏輯,而想要得到其他系統介面的特定輸出,需要做相應的運營配置,增加很多的溝通成本;甚至偶發性 bug 只能在特定的環境狀況下復現,只能作為不可測的邏輯。

以風控系統為例,如果業務系統需要測試某個商編某個商品類別下的累積限額,需要風控的同事配合不斷修改限額閾值,目前的情況是多個業務系統都在接入風控,配合測試的人力成本和時間成本是很高的。為此設計了擋板模擬系統,其功能結構如下:

針對測試人員測試用例資料無法沉澱和複用的問題,我們將採用“用例與日誌錨點庫”方案:

  • 用例庫的建立可以實現對以往測試規則的記錄與複用,改變每次迴歸測試都要重複編寫用例與準備資料的現狀。

  • 日誌錨點庫是對程式碼執行流程的有效驗證,除了可以應用在測試環境中,還可基於大資料日誌中心對生產程式碼的執行做日常監控。

  • 交易與支付系統業務邏輯複雜,靠人腦和文件記憶功能關係難免疏漏,而用例庫和日誌錨點庫會隨著業務的變更測試而隨即維護,是一部活文件。

Mock 系統的技術方案

1、系統的功能點

說明: 上圖羅列了整個 Mock 測試系統的功能點有哪些,共分為:配置介面資料、建立測試用例、建立測試集、建立測試計劃、執行測試計劃以及生成測試報告等大功能。

配置介面資料介面圖

建立測試用例配置圖

擋板請求路由配置圖

測試執行結果

2、系統的功能流程圖

說明:依據上下文環境,利用工廠類動態注入 spring 對遠端介面的依賴,保持線上與測試的程式碼一致。在測試環境中,通過 mock 系統管理端,可以隨時調整請求的流向,“指哪打哪”。

說明:執行某項測試用例, 利用 mock 將被測試介面與底層依賴介面隔離開來,可以方便的模擬資料,並監控輸入輸出。用例執行完畢後,使用返回斷言、SQL 查詢、日誌標記等多種手段驗證。

Dubbo 的 Mock 功能

1、Dubbo 的 Mock 使用

Dubbo 自帶的 Mock 功能首先是為了做服務降級,比如某驗權服務,當服務提供方全部掛掉後,客戶端不丟擲異常,而是通過 Mock 資料返回授權失敗。

我們從官網上舉一個例子來說明:

我們可以在期望的 reference 標籤上加一個 mock="force",就可以將當前服務設定為 mock。但是設定完 mock 屬性後還沒有結束,需要有一個 Mock 類對應我們的服務介面類。

規則如下:

介面名 + Mock 字尾,服務介面呼叫失敗 Mock 實現類,該 Mock 類必須有一個無參建構函式。

對應到 com.foo.BarService 的話,則建立 BarServiceMock 類。

經過以上設定後,當呼叫 BarService 進行遠端呼叫的話,直接請求到 BarServiceMock 類上面進行模擬測試。

2、Dubbo Mock 的原理解析

在 dubbo 的配置檔案中

可以看到如下配置列表:

我們可以看到配置檔案中實際上有五大路由策略:

  • AvailableCluster: 獲取可用的呼叫。遍歷所有 Invokers 判斷 Invoker.isAvalible, 只要一個有為 true 直接呼叫返回,不管成不成功。

  • BroadcastCluster: 廣播呼叫。遍歷所有 Invokers, 逐個呼叫每個呼叫 catch 住異常不影響其他 invoker 呼叫。

  • FailbackCluster: 失敗自動恢復, 對於 invoker 呼叫失敗, 後臺記錄失敗請求,任務定時重發, 通常用於通知。

  • FailfastCluster: 快速失敗,只發起一次呼叫,失敗立即保錯,通常用於非冪等性操作。

  • FailoverCluster: 失敗轉移,當出現失敗,重試其它伺服器,通常用於讀操作,但重試會帶來更長延遲。

Dubbo 中預設使用的是 FailoverCluster 策略,而在實際執行的過程中是 FailoverCluster 會被先被注入到 MockClusterWrapper 中,過程就是:

MockClusterWrapper 內部會建立一個 MockClusterInvoker 物件。實際建立是封裝了 FailoverClusterInvoker 的 MockClusterInvoker,這樣就成功地在 Invoker 之中植入了 Mock 機制。

我們來看 MockClusterInvoker 的內部實現:

如果在沒有配置之中沒有設定 mock,那麼直接把方法呼叫轉發給實際的 Invoker(也就是 FailoverClusterInvoker)。

如果配置了強制執行 Mock,比如發生服務降級,那麼直接按照配置執行 mock 之後返回。

如果是其它的情況,比如只是配置的是 mock=fail:return null,那麼就是在正常的調用出現異常的時候按照配置執行 mock。

3、Dubbo Mock 的適用場景

Dubbo 的 Mock 功能主要是為了做服務降級而使用的,服務提供方在客戶端執行容錯邏輯,在出現 RpcException(比如網路失敗,超時等) 時進行容錯,然後執行降級 Mock 邏輯。自身並不適合做 Mock 測試系統。

自動化 Mock 系統的實現

1、Mock 系統的簡單用例圖

2、Mock 系統的架構圖​​​​​​​

為了基於 Dubbo 實現 Mock 功能,需要對 Dubbo 原始碼進行一些必要的修改,通過上面的架構圖我們可以看到,實際上我們正是利用了 Dubbo 的 Filter chain 過濾器鏈這一機制實現的,為了方便大家更好的理解,下面將簡單介紹一下 Dubbo 的 Filter 機制。

 Dubbo 的 Filter 原理分析

Filter:是一種遞迴的鏈式呼叫,用來在遠端呼叫真正執行的前後加入一些邏輯,跟 aop 的攔截器 servlet 中 filter 概念一樣的。

Filter 介面定義:

Filter 的實現類需要打上 @Activate 註解, @Activate 的 group 屬性是個 string 陣列,我們可以通過這個屬性來指定這個 filter 是在 consumer, provider 還是兩者情況下啟用,所謂啟用就是能夠被獲取,組成 filter 鏈。

關於 SPI 的詳細介紹請大家參考我之前寫的另一篇文章:

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

ProtocolFilterWrapper:在服務的暴露與引用的過程中根據 KEY 是 PROVIDER 還是 CONSUMER 來構建服務提供者與消費者的呼叫過濾器鏈,Filter 最終都要被封裝到 Wrapper 中的。

構建 filter 鏈,當我們獲取啟用的 filter 集合後就通過 ProtocolFilterWrapper 類中的 buildInvokerChain 方法來構建。

 Mock 流程介紹

注:我們在中新加了自定義的“env=test”這樣的屬性配置用來標明當前環境是測試的還是正式的,使用者每次通過 Dubbo 請求的遠端服務的時候,都會首先經過我們自定義的 Filter,我們自定義的 Filter 會首先判斷當前的環境是 test 還是正式,如果是 test 的環境則直接訪問 Mock 配置中心獲取提前配置好的 Mock 資料並封裝成使用者定義的 Response 物件返回。

3、Mock 系統的配置中心

Mock 配置中心就是使用者將 mock 資料與應用環境建立關係的系統,整個系統就像一個工作流引擎:

環境設定 ->應用名稱設定 ->擋板規則設定 ->Facade 服務介面設定 ->方法規則設定

環境設定

注:如果尚未對映來源 IP 地址到環境,則點選環境列表導航連結,進入環境列表頁面,點選新增,輸入源 IP 及環境名,點選確定按鈕,實現源 IP 到所設環境的對映。每個使用者都可以建立屬於自己的測試環境。

應用名稱設定

注:建立所使用系統的應用名稱,Mock 配置中心預設使用中的名稱作為應用名稱。

擋板規則

注:每一個擋板規則都是由一個環境名稱和應用名稱組成的唯一擋板,在擋板設定中選擇環境名稱和應用名稱,並且設定擋板的有效狀態。

Facade 規則

注:每一個 Facade 就是一個 Dubbo 的服務介面類,在這裡將自己的 Facade 名稱與全路徑與擋板名稱對應,以標識哪些 Facade 服務介面類是屬於哪個擋板的。

方法規則

注:方法規則是用來設定每個 Facade 中的需要 mock 的方法的,可以對不同的方法設定方法執行時間、方法丟擲的異常等等。

4、Mock 系統的其他功能

由於不少應用專案開發完後想對其進行單獨壓測,而很多時候應用系統和其他業務系統形成了依賴關係,如果不佈署其他應用系統則無法完成壓測,為了更好的支援效能測試組進行擋板壓測,Mock 系統支援壓測功能,而 Mock 系統自身也可以達到單臺伺服器 1000TPS 以上(8C8G)。