本文介紹一種前端灰度發佈方案,主要解決的是傳統的灰度發佈只能以機器維度進行分組的問題。提供一種用戶維度分組的灰度發佈機制。前端
傳統灰度發佈,由於是以機器分組,因此要求服務是無狀態的。所謂無狀態就是對請求的處理是上下文無關的。有長鏈接、讀寫文件、緩存等場景,就是所謂」有狀態「的。有狀態的服務,若是用戶的前一個請求打在機器A,後一個請求打在機器B,就會出問題。node
因此,有狀態的服務灰度發佈,要作到:webpack
本灰度發佈方案對構建、部署、啓動服務、處理請求階段分別作改造,實現有狀態服務灰度發佈。git
咱們把線上的代碼稱爲stable版,本次發佈的新代碼稱爲beta版。先總體描述一下方案:web
正常開發代碼,無需有任何額外操做。算法
新增一個git tag,以p-開頭,意爲publish。每次發佈都有一個tag標記,格式爲p-201911111001-lvdabao.標記發佈時間與發佈者。構建完成並同步cdn成功後,會將該tag同步到git倉庫。json
manifest.json是webpack構建完畢後的文件清單,能夠用webpack-manifest-plugin插件生成。若有特殊需求也能夠本身編寫。咱們是本身編寫,並在動態渲染首頁HTML時讀取清單內容並輸出script標籤。緩存
每次構建生成的文件名稱是這樣的格式:manifest-p-201911111001-lvdabao.json,這樣每次發佈都生成對應tag命名的manifest.json文件。cookie
啓動服務時能夠一次讀取到內存中,並非處理每一個請求都讀一下文件,因此沒必要擔憂性能。性能
咱們是用publish-tag來標識版本號的,只要拿到上次發佈時的tag,就能取到對應的manifest.json文件。因此構建的最後一步就是把上一版的manifest.json文件從cdn源機器取到當前構建後的dist目錄下,爲後續服務啓動時使用。
取上次的tag也很簡單,一個git命令搞定:git tag --sort=-taggerdate | grep "^p-.*" | head -n 1
若是上次發佈的版本有重大問題,不能做爲stable版使用,有什麼辦法呢?
因此咱們增長了一個額外流程,容許構建的時候傳入環境變量,指定stable tag。這樣在獲取stable版本信息時,優先取環境變量中指定的。
部署跟普通流程沒什麼區別,將dist目錄發佈到目標機器就好了。每次部署的dist文件包含如下:
由於stable版的資源文件已經在cdn了,因此本次部署沒必要管他們。
啓動服務時咱們須要幹兩件事情:
上面提到了放量配置,這個是放在單獨的配置系統中的,固然簡單點放在服務端也是能夠的。用途就是根據當前用戶的uuid,來肯定用戶該使用哪一個版本的資源。
配置內容也及其簡單:
{ percent: 10 }
percent便是beta版的放量比例,10表示10%的用戶使用beta版。全量的時候手動改成100就行啦。
由於啓動服務的時候會自動將percent改成0,因此每次發佈完後,咱們只需根據放量節奏逐步擴大percent的值就好。
萬事具有,咱們在處理請求的時候,就很easy了。只需獲取當前用戶的uuid,node層經過RPC調用獲取到放量配置,經過分流策略來計算應該使用哪一個版本的資源。
咱們的首頁是動態輸出的(SSR),拿到分流策略得出的tag,把相應的manifest.json中的文件輸出,這樣就控制了哪部分用戶使用beta版本。
最後再談談分流策略,這塊也是有不少細節的。分流策略要作的核心工做:
首先,放量配置只有一個百分比數字,咱們須要把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。
以上就是灰度發佈方案的核心內容啦,相關的代碼細節不贅述,有讀者朋友感興趣能夠留言探討。
經過這套方案咱們實現了以用戶維度進行分組的灰度發佈,而且整個流程足夠自動化,業務開發無感知,須要手動操做的只有修改放量配置。
有朋友可能想說,你這個方案和ABTest很類似啊!其實ABTest和本方案的差異主要有:
儘管看起來差異不大,但ABTest方案的構建、部署、分流控制都會有所區別。
固然,若是咱們把ABTest退一步,認爲stable版是A,新上線代碼是B,那麼將本方案改形成ABTest方案也很容易。