多feature測試時後端測試環境管理的一種方案設想

背景

假如咱們有一組後端服務爲用戶提供某些功能,各服務之間的調用關係(簡化的)可能以下圖前端

test1

在實際的工做中,咱們常常遇到這種場景:同時有多個feature在開發,好比feature_x,feature_y,feature_z,json

這些feature的代碼改動可能涉及到若干個相同或者不一樣的的後端服務,例如:後端

1)feature_x修改了app_srv0的<用戶帳戶展現> 接口(假設該接口的名字是user_account_show),user_account_show接口依賴app_srv1的 <帳戶餘額接口>user_account_balanceapp

2)feature_y特性修改了user_account_balance接口,這個修改承諾接口的對外輸出不改變,只是修改了用戶的帳戶餘額計算公式。框架

在feature_y測試經過以前」user_account_balance接口對外輸出不改變「這個承諾是沒法獲得保障的,若是咱們只有一個測試環境,多個feature都只能在這個測試環境上進行測試,那麼feature_x,feature_y的測試只能串行。若是並行進行測試的話,服務部署會是下面這個樣子的(淺綠表示feature_x,紫色表示feature_y):性能

test2

測試過程當中若是feature_y有bug致使user_account_balance返回的數據不對,就會間接致使user_account_show接口返回的展現信息也不對,從而致使測試認爲。但實際feature_x的修改。測試

經常使用的解決辦法

1)測試串行,缺點:時間週期常,項目feature上線慢spa

2)並行部署多套測試環境,缺點:資源成本和維護成本都很高,若是服務衆多或者並行開發的版本多那麼基本不具有可執行性3d

3)使用一套環境強行並行測試,缺點:特性之間的相互影響可能致使多個特性的測試都須要返工,拖長各個feature測試的耗時code

解決方案設想

先不廢話,上個圖

由上面的分析咱們能夠知道要考慮的是「怎麼已較小的代價實現測試環境特性隔離」,「代價小」也就是儘量少的部署服務,只部署有修改的服務便可;「特性隔離」就是不一樣特性分支的請求分別路由到支持對應特性的服務版本上。參考上圖:

feature_x修改了app_srv1,app_srv4,app_srv6,分別獲得新版本服務app_srv1_x,app_srv4_x,app_srv6_x

feature_y修改了app_srv4,app_srv7,分別獲得新版本服務app_srv4_y,app_srv7_y

假設feature_x版本的請求爲Rx,feature_y版本的請求爲Ry,基線版本的請求爲R0,只要作到Rx,Ry請求分別走不一樣的調用鏈便可保證feature_x和feature_y的測試相互不影響,也就是:

Rx的調用鏈:app_srv0 —> app_srv1_x —> app_srv2 —> app_srv4_x —> app_srv6_x —> app_srv7

Ry的調用鏈:app_srv0 —> app_srv1 —> app_srv2 —> app_srv4_y —> app_srv6 —> app_srv7_y

如何作到這一點

讓請求攜帶路由信息(如下格式爲非標準json格式,只是相似格式方便展現而已)

在請求的公共頭部攜帶一個版本綁定的路由信息,好比編號feature_x_20180101,feature_y_20180101

//feature_x
//comm_head
{
  "route_id":"feature_x_20180101"
}

//feature_y 
//comm_head
{
  "route_id:feature_y_20180101"
}
複製代碼

存儲一張路由表

//route_table
{
  "feature_x_20180101": [
    {
      "appid": "app_srv1",
      "srv_version": "app_srv1_xxx",
      "addr": "ip:port"
    },
    {
      "appid": "app_srv4",
      "srv_version": "app_srv4_xxx",
      "addr": "ip:port"
    },
    {
      "appid": "app_srv1",
      "srv_version": "app_srv6_xxx",
      "addr": "ip:port"
    }
  ],
  "feature_y_20180101": [
    {
      "appid": "app_srv4",
      "srv_version": "app_srv4_yyy",
      "addr": "ip:port"
    },
    {
      "appid": "app_srv7",
      "srv_version": "app_srv7_yyy",
      "addr": "ip:port"
    }
  ]
}
複製代碼

每一個服務維護本身的appid,發起rpc的服務經過某種方式獲取路由表配置,從獲取的路由表中尋找映射的appid,和被調用目標appid(調用方必定知道被掉方的appid)進行對比,找到須要調用的服務地址和端口,例如:

feature_x的請求Rx到達app_srv0以後,app_srv0須要調用app_srv1,app_srv0解析出請求頭部(comm_head)的route_id:feature_x_20180101,使用route_id獲取到路由表feature_x_20180101項下面的全部配置,從得到的配置中尋找appid=app_srv1的項(這裏服務的數量是頗有限的,沒必要擔憂遍歷的性能),獲取對應的ip和端口發起調用,這樣就能夠是Rx請求觸發的第一次rpc調用的是feature_x版本的app_srv1_x而不是基線版本的app_srv1或者feature_y版本的app_srv1_y,若是找不到對應的想就採用默認路由調用,也就是調用基線版本;發起調用的時候透傳請求頭裏面的route_id,這樣後續調用鏈的每一個服務都能使用上述過程找到請求要調用的版本分支,這裏須要增長的就是對路由表的維護工做以及客戶端發起請求的時候須要增長請求頭的寫入。發佈上線以後也能夠採用這種方法進行AB test,若是不須要能夠對配置進行修改或者前端發起請求的時候不攜帶路由信息。

路由表的管理和維護

1)交給mesh

2)服務發佈的時候經過註冊中心註冊本身版本的路由信息,經過註冊中心下發到各服務所在的機器,服務框架經過agent從本地讀取配置

本身的一點思考,歡迎更多交流!!!

相關文章
相關標籤/搜索