一種前端灰度發佈方案

點擊上方 "程序員小樂"關注, 星標或置頂一起成長

每天凌晨00點00分, 第一時間與你相約


每日英文

Say not all that you know, believe not all that you hear.

你所知道的不要全說,你所聽到的不要全信。


每日掏心話

做人不要太玻璃心,不要別人一條信息沒回,就覺得自己做錯了什麼,不要被人一句”呵呵“,就覺得對方是討厭自己。玻璃心,想太多,什麼事都對號入座,何必那麼累。


鏈接:cnblogs.com/lvdabao/p/11920919.html

一種前端灰度發佈方案

程序員小樂(ID:study_tech)第 766 次推文 圖片來自 Pexels


往日回顧:鍾南山再談疫情:確診數增加會持續但不會太久!目前病死率2.3%-2.4%比非典低


正文


本文介紹一種前端灰度發佈方案,主要解決的是傳統的灰度發佈只能以機器維度進行分組的問題。提供一種用戶維度分組的灰度發佈機制。


傳統灰度發佈,因為是以機器分組,所以要求服務是無狀態的。所謂無狀態就是對請求的處理是上下文無關的。有長連接、讀寫文件、緩存等場景,就是所謂”有狀態“的。有狀態的服務,如果用戶的前一個請求打在機器A,後一個請求打在機器B,就會出問題。


所以,有狀態的服務灰度發佈,要做到:


  • 同一用戶始終訪問同一版本的代碼

  • 放量過程像傳統發佈一樣可控


本灰度發佈方案對構建、部署、啟動服務、處理請求階段分別做改造,實現有狀態服務灰度發佈。


1、方案概述


我們把線上的代碼稱為stable版,本次發佈的新代碼稱為beta版。先整體描述一下方案:


  • 用git tag標識每次發佈

  • 在構建階段生成tag,同時用tag名稱來命名manifest.json

  • 每次構建完新版本後,從cdn源機器取回上次發佈的manifest.json文件,一併放在dist目錄下

  • 部署階段全量部署到所有機器,在運行階段來決定訪問哪個版本的代碼

  • node層啟動服務時,讀dist目錄下的兩份manifest.json文件,這樣就能拿到新舊兩個版本的文件清單

  • 處理請求時,根據動態配置的放量信息和分流策略,來決定使用哪個manifest.json中的文件

  • 版本號信息放在cookie中,以保證同一用戶始終訪問同一版本代碼


2、開發階段


正常開發代碼,無需有任何額外操作。


3、構建階段


publish-tag


新增一個git tag,以p-開頭,意為publish。每次發佈都有一個tag標記,格式為p-201911111001-lvdabao.標記發佈時間與發佈者。構建完成並同步cdn成功後,會將該tag同步到git倉庫。


manifest.json


manifest.json是webpack構建完畢後的文件清單,可以用webpack-manifest-plugin插件生成。如有特殊需求也可以自己編寫。我們是自己編寫,並在動態渲染首頁HTML時讀取清單內容並輸出script標籤。


每次構建生成的文件名稱是這樣的格式:manifest-p-201911111001-lvdabao.json,這樣每次發佈都生成對應tag命名的manifest.json文件。


啟動服務時可以一次讀取到內存中,並不是處理每個請求都讀一下文件,所以不必擔心性能。


獲取上次發佈的版本信息


我們是用publish-tag來標識版本號的,只要拿到上次發佈時的tag,就能取到對應的manifest.json文件。所以構建的最後一步就是把上一版的manifest.json文件從cdn源機器取到當前構建後的dist目錄下,為後續服務啟動時使用。


取上次的tag也很簡單,一個git命令搞定:git tag --sort=-taggerdate | grep "^p-.*" | head -n 1


容錯機制


如果上次發佈的版本有重大問題,不能作為stable版使用,有什麼辦法呢?

所以我們增加了一個額外流程,允許構建的時候傳入環境變量,指定stable tag。這樣在獲取stable版本信息時,優先取環境變量中指定的。


4、部署階段


部署跟普通流程沒什麼區別,將dist目錄發佈到目標機器就行了。每次部署的dist文件包含以下:


  • beta版的manifest.json文件

  • beta版的資源文件

  • stable版的manifest.json文件


5、啟動服務


啟動服務時我們需要幹兩件事情:


  • 把兩個manifest.json文件讀到內存中,供分流時使用

  • 自動修改放量配置,將新版本比例改為


6、放量配置


上面提到了放量配置,這個是放在單獨的配置系統中的,當然簡單點放在服務端也是可以的。用途就是根據當前用戶的uuid,來確定用戶該使用哪個版本的資源。


配置內容也及其簡單:


{
percent: 10
}


percent即是beta版的放量比例,10表示10%的用戶使用beta版。全量的時候手動改為100就行啦。


因為啟動服務的時候會自動將percent改為0,所以每次發佈完後,我們只需根據放量節奏逐步擴大percent的值就好。


7、處理請求


萬事具備,我們在處理請求的時候,就很easy了。只需獲取當前用戶的uuid,node層通過RPC調用獲取到放量配置,通過分流策略來計算應該使用哪個版本的資源。


我們的首頁是動態輸出的(SSR),拿到分流策略得出的tag,把相應的manifest.json中的文件輸出,這樣就控制了哪部分用戶使用beta版本。


8、分流策略


最後再談談分流策略,這塊也是有很多細節的。分流策略要做的核心工作:


  • 根據放量配置來決定當前用戶應使用的資源版本

  • 確保用戶的分流路線穩定,即下次請求頁面應與上次的分流結果一致

  • 新版本發佈或放量比例變化時,重新分流


首先,放量配置只有一個百分比數字,我們需要把uuid散列化,即把uuid字符串對應到0-99間固定的數字。算法可以有很多,我們選一種簡單的,取每個字符的ASCII碼相加,然後再除100取餘。偽代碼:


for (i = 0; i < uuid.length; i++) {
hash += uuid.charCodeAt(i);
}


取到的這個hash就可以與放量百分比比較,在範圍內就使用beta版。


另外一個比較麻煩的事情是第2點,為了讓用戶下次訪問的時候能夠跟首次的分流一致,我們需要把首次分流的結果保存在cookie中。當請求來的時候先分析cookie中的版本信息,如果可用則優先用cookie。不可用的話清掉cookie,再去計算分流。


那麼既然uuid的散列算法能保證hash值穩定,每次都用uuid計算不行嗎?原因就是我們訪問環境的特殊,uuid的穩定性不能保證,相對來說還是cookie更穩定。這個看項目吧,如果你的項目uuid穩定,那可以省去用cookie。


8、總結


以上就是灰度發佈方案的核心內容啦,相關的代碼細節不贅述,有讀者朋友感興趣可以留言探討。


通過這套方案我們實現了以用戶維度進行分組的灰度發佈,並且整個流程足夠自動化,業務開發無感知,需要手動操作的只有修改放量配置。


有朋友可能想說,你這個方案和ABTest很相似啊!其實ABTest和本方案的差別主要有:


  • 需要同時上線AB兩套新代碼

  • 最終會丟棄其中一套代碼


儘管看起來差別不大,但ABTest方案的構建、部署、分流控制都會有所區別。


當然,如果我們把ABTest退一步,認為stable版是A,新上線代碼是B,那麼將本方案改造成ABTest方案也很容易。


一種前端灰度發佈方案

歡迎在留言區留下你的觀點,一起討論提高。如果今天的文章讓你有新的啟發,學習能力的提升上有新的認識,歡迎轉發分享給更多人。


猜你還想看


阿里、騰訊、百度、華為、京東最新面試題彙集

怎樣提供一個好的移動 API 接口服務

高併發下的抽獎優化

這些方法,能夠讓你的Python程序快如閃電


關注訂閱號「程序員小樂」,收看更多精彩內容
嘿,你在看嗎?


分享到:


相關文章: