1. 程式人生 > >灰度釋出系統的實現

灰度釋出系統的實現

               

灰度釋出,已經不是一個很新的概念了.一個產品,如果需要快速迭代開發上線,又要保證質量,保證剛上線的系統,一旦出現問題那麼可以很快的控制影響面,就需要設計一套灰度釋出系統.

灰度釋出系統的作用在於,可以根據自己的配置,來將使用者的流量導到新上線的系統上,來快速驗證新的功能修改,而一旦出問題,也可以馬上的恢復,簡單的說,就是一套A/BTest系統.

它大抵的架構,應該是類似這樣的:

其中分為幾個部分:

  1. 接入層,接入客戶端請求,根據下發的配置將符合條件的請求轉發到新舊系統上.
  2. 配置管理後臺,這個後臺可以配置不同的轉發策略給接入層.
  3. 新舊兩種處理客戶端請求的業務伺服器.

關於接入策略的設計上,從協議層來說,需要從一開始就設計是根據哪些引數來進行轉發的,而且這些引數最好跟具體的協議體內容分開,這樣減少接入層對協議的解析.舉個例子,如果客戶端的請求是走HTTP協議的,那麼將這些引數放在HEADER部分就好了,接入層不需要去具體解析body部分的資料就拿到了轉發策略需要的引數.當然,放在HEADER中的資料,因為沒有了加密性,又是需要考慮的另一個問題.

當然,最簡單粗暴的轉發策略,可以根據客戶端ip地址來做,這是比較粗略的一個劃分策略.

同樣的,新舊伺服器要對新舊客戶端的協議相容,也是能做到灰度釋出的根本,如何設計一個擴充套件性好的應用協議,這一點就不在這裡考慮了.

接下來,還需要滿足如果管理後臺下發了新的轉發策略,接入層應該是可以馬上感知到然後切換到這個新的策略來的.有好些不同的做法.假如接入層是Nginx這樣的伺服器,使用者只是在上面寫了自己的Nginx模組來實現策略的轉發,那麼可能還需要在每臺接入伺服器上部署一個Agent的服務,主要用於:

  1. 接收管理後臺下發的策略,更新Nginx配置,然後優雅重啟Nginx服務.
  2. 定時檢查本臺機器的Nginx服務的狀態,進行上報.

如果接入層不是Nginx這樣的服務,那麼也可以做一個pub-sub模型的訂閱者,用ZK或者Redis都可以,訂閱管理後臺下發的服務進行處理即可.

上週寫完灰度釋出系統相關的博文之後,有朋友表示灰度系統的實現太過簡單了,因為我目前接觸的系統確實比較簡單,很多複雜的東西沒有考慮周全,如果更大型的業務系統,涉及到的服務更多,還有如果摻雜著資料的遷移,就更復雜了.這裡就把當時討論的內容提取出來,主要的貢獻者為滴滴的沈佳偉.

1.呼叫鏈上有多個業務服務的場景

考慮這樣一個業務場景,假設對外提供了服務A給客戶端訪問,服務A後面會呼叫服務B,C,D,此時需要上線一個功能,這個功能涉及到了服務A,C的修改,但是服務B,D不需要變動,換言之,我們的意圖是,如果一個客戶端請求,走到了新的灰度服務A,那麼最終這個請求也應該走到這次和A一起灰度的服務C上.

這裡的處理策略,可以給客戶端請求進行tag打標記的方式,比如經由新版本服務A處理的請求,全部打上tag A,而在服務C上,也有接入層進行轉發,它轉發的策略之一就是根據根據這個tag來進行轉發,這個系統如下圖所示:

上圖中,請求首先走到了舊版本的服務A上,該服務沒有對請求打上tag,所以後續訪問的都是沒有配套灰度的舊版本C服務.

上圖中,請求首先走到了新版本需要灰度的服務A上,在經過該服務處理後,給請求打上了tag A,由於帶上了tag,後續訪問的都是配套灰度的C服務.

簡單的總結下,涉及到一個呼叫鏈路上某幾個服務需要灰度的情況,可以通過tag的方式,將走灰度服務的請求彙集到一起來,如果一個請求走到了一個灰度路徑上,就打上一個tag,這樣只有有這個tag的請求才能走到這條鏈路上後續也需要一起灰度的服務上.至於如何給請求打tag,如果是HTTP協議,那就很簡單了,也是加Header的方式,否則需要在設計協議的時候就考慮協議的擴充套件性支援這個操作.

2. 涉及到資料的灰度服務

假設灰度的服務,需要使用到資料庫,如果灰度前後資料庫的欄位保持不變,那麼新舊兩套系統使用同一套資料庫就可以了.

如果前後資料不一致,需要處理的情況就比較複雜,分為以下幾種情況.

  • 部分灰度

在部分灰度的情況下,有部分請求到舊系統上,另一部分請求到了新的灰度系統上.走到舊系統的請求,還是照原樣處理.但是走到了新版灰度系統的請求,需要同時將請求轉發給舊系統上來對應的介面上修改舊系統的資料.如果走到新系統的請求查不到該使用者的資料,還需要首先同步一份來新系統上.如果是事務性的請求,以寫入老系統成功來做為操作成功的標準.

  • 全部灰度

在灰度系統已經全部接管了線上流量之後,為了安全起見,仍然需要對新老系統進行雙寫,步驟和前面一樣.

  • 灰度完成

灰度完成與前面的全量灰度狀態不太一樣,區別在於前面的全量灰度狀態下,仍然不能肯定系統一定是沒有問題的,所以需要進行新舊系統的雙寫來保證資料可以在老系統上進行回滾.而在灰度完成狀態,此時認為這個新版本已經完全通過了驗證,無需再寫入舊系統了.但是此時可能存在部分在灰度期間沒有上線的使用者,此時需要做一次同步,從舊系統上將這部分資料同步過來.

可以看到,這三個狀態下,對新舊系統是否進行雙寫,做了嚴格的區分,目的只有一個:一旦新上線的系統出現問題,可以馬上撤掉灰度系統,而這期間使用者的任何修改在舊系統上都是可以找到的.