基於Nodejs的前端灰度發佈方案_20190228

基於Nodejs的前端灰度發佈方案

1. 灰度發佈和A/B測試簡介

灰度發佈

將某個功能灰度發佈(逐漸放量)給特定線上人羣,避免新功能全量上線帶來的風險。javascript

上面的圖能夠經過兩個方面來理解css

  1. 藍色實線和藍色虛線訪問Nginx服務器,nginx經過負載均衡將流量分攤到後端服務器。
  2. 黃色的線是應用了灰度的流量(配置Nginx規則)能夠將特定流量分發到特定的機房,以達到對特定用戶應用產品新功能;
舉個簡單的例子:將http請求cookie中含有test=1字段的請求都轉發到灰度代碼的機房;

上面經過經過配置特定Nginx規則的方法來達到產品灰度的方法雖然能夠知足必定業務量的需求,可是他也有不少的缺點html

  1. 不靈活,每次上線新業務代碼須要作灰度都要從新更新nginx規則,形成開發和運維負擔;
  2. 上線的代碼要作機房區分,不可以將代碼全量。本地的Git代碼也要區分開發分支和測試分支,線上分支等若干分支,管理起開麻煩;
  3. 不能知足業務量大或者業務須要頻繁迭代,須要頻繁作測試的業務;

那麼有沒有更好的方法來作灰度發佈呢?固然是有的,A/B測試就可以彌補上面經過Nginx規則來作灰度的缺點。前端

A/B測試

將線上一部分真實人羣流量隨機拆分紅多個組,對每一個分組的人羣應用不一樣策略或功能,經過計算每組人羣的業務指標(轉化率、成交率等)來衡量策略或功能的實際效果。java

咱們經過下面的這張圖簡單的瞭解下A/B測試的原理:
node

由上圖咱們能夠知道A/B和傳統的灰度方法的區別:webpack

傳統的灰度是經過Nginx分發流量到服務器,A/B測試是經過業務代碼區分流量訪問不一樣的代碼塊。nginx

那麼A/B測試的優缺點是什麼呢?git

優勢:web

  1. 隨着業務的變化不用頻繁的變化Nginx規則,不用分機房上線業務代碼,本地git分支不用爲了作灰度而建專門的分支;
  2. 流量區分是業務代碼作的。因此上線代碼的時候能夠全量上線到全部機房;

缺點:

  1. 由於流量區分是業務代碼作的。因此在代碼中會存在不少的if...else分支語句。可是這樣還好,由於根據SDK的規範來書寫代碼,仍是很好管理的。

2. 基於A/B測試的前端灰度怎麼作

前端跟後端很大的區別就是直接面對用戶,就算很簡單的修改一次按鈕的顏色就須要一次上線。這種操做對用戶是可感知的。

現代前端有個特色就是脫離了後端模板引擎的渲染,大多數是使用React、Vue這種MVVM框架的前端(瀏覽器)渲染。這種狀況下後端其實僅僅是給用戶提供一個空的html文件(工做中常常稱做爲殼)。大多數業務代碼開發完之後都是做爲靜態文件上線到服務器,通過用戶訪問後緩存到CDN節點上的。並且這個過程大多數是增量上線的。

其實咱們每次上線完以後服務器上緩存的html文件就包含不一樣的版本信息。若是咱們把這些版本信息管理起來,而且經過特定的手段(對用戶請求應用A/B測試)就能夠完成前端不一樣版本的灰度發佈。

使用Nodejs靈活控制前端發佈

咱們能夠觀察下Webpack或者是其它打包工具打包後的html文件。每次外聯的靜態文件都包含不一樣的hash戳。這些外鏈的文件又都是增量緩存到服務其上的。

index.html (咱們頁面的「殼」)
一些 xxx.js文件 (渲染頁面+頁面的業務邏輯)
xxx.css 文件 (控制頁面顯示樣式)

大概就是下面的這個樣子

基於以上的特色,咱們能不能儘可能減小對業務代碼侵入,而能夠覆蓋業務改動較大的需求進行灰度或者是A/B測試呢?

看下下面的這個這個請求的圖:

每次咱們打包編譯完以後,就將相關的css文件和js文件信息保存到本地的一個json文件中。這些信息的key能夠是咱們的git的tag信息(主要來描述本次發版信息包含的功能等)。

基本上json文件包含的信息以下:

const version = {
  // 能夠描述本次的上線內容/ 或者是git tag
  'tag1': {
    'css': 'xxxxxxx.css',
    'app': 'app_xxx.js',
    'ventor': 'ver_xxx.js'
  }
}
這裏僅僅是一個簡單的demo示例,可使用Nodejs寫文件的特性直接將文件版本號寫入到index.html返回給前端瀏覽器

Nodejs服務的特色是每次更新完代碼須要重啓以後才能生效。每次上完線重啓服務就會先檢查本地代碼根目錄下的這個json文件。看下這個其中包含的tag是否在DB中存儲,若是有存儲就不作操做,若是沒有就將它存儲DB作持久化。

上面圖上面的Apollo就是用來配置那些用戶訪問新功能的平臺。在Nodejs端,每次接收到用戶請求的時候都會判斷用戶的信息是否知足相關條件,而後從DB中讀取相關靜態文件信息渲染到index.html中去。

簡單總結下:將每次打包的靜態文件信息先存儲下來,以後請求到達Nodejs的時候判斷用戶是否知足相關條件,若是知足就讀取DB將相關的靜態文件信息返回給Nodejs,Nodejs將靜態頁渲染好以後返回給用戶,達到灰度的目的。

3.其它細節問題

使用Nodejs以前咱們的頁面就是直接部署在服務其上,此次使用了Nodejs後,會有不少其它的問題須要作,好比說Nodejs服務的監控,多機房部署等。這些在大部分的公司應該都有相關的運維工程師來作。我這裏簡單介紹一些其它的內容

規範的肯定

這裏的規範包括本地開發時工程目錄的規範和線上用戶訪問url的規範。

  • 開發目錄規範

在筆者寫這篇文章的時候最新的Nodejs版本已是 11.10版本了,最新的LTS版本是10.15.1版本。建議使用Nodejs的同窗都升級本身的Node到8.0版本以上,由於8.0版本是一個官方原生支持async...await語句的版本。

.
├── client // 放置客戶端的代碼
├── index.html
├── index.js
├── node_modules
├── output
├── package-lock.json
├── package.json
├── server // 放置服務端Nodejs代碼
├── test.sh

須要注意的就是在編寫webpack打包工具的時候將server目錄下的給排除掉。放置沒必要要的編譯和產出,增長打包速度。
  • 線上url的約定

當使用了新的服務的時候爲了防止跟舊業務的衝突確定須要使用新的url。這個時候就須要作一些約定。目前咱們是這麼約定的

// 域名/產品線/模塊/
http://wwww.aaa.com/driver/bus/index.html
// 域名/產品線/模塊/靜態文件目錄
http://wwww.aaa.com/driver/bus/static/js/index.js
http://wwww.aaa.com/driver/bus/static/css/index.html

兼容老業務須要作的工做

前面提到此次業務升級咱們使用了新的url,可是爲了保證業務的穩定性咱們不是一次性將全部的流量都切到新服務上去的。咱們也是經過批量的切的,因此會存在線上用戶有的地區訪問新服務有地區訪問舊服務。那麼有一天會有所有切換的一天,可是仍是會有一些用戶訪問到舊連接,這個時候能夠經過配置Nginx 的`rewrite來說舊連接都轉成新的連接。

  1. 升級後的業務怎麼訪問新的鏈接
  2. 已經請求相關的配置

避免沒必要要的請求

前端路由能夠分爲兩種方式,hash和path切換。由於對於前端渲染頁面來講,當第一次請求完成後,其實全部的頁面都已經下載到了本地(頁面異步加載除外)。在咱們經過path切換頁面的時候,每次都會向服務端發送請求,其實這些請求是不須要到達Nodejs服務的。咱們能夠經過Nginx配置將這些無用的流量抵擋在Nginx這一層,減小服務器的壓力。

若是是使用hash的方式則不存在這樣的問題,可是會有另外的問題就是對搜索引擎不友好。固然前端路由切換仍是應該根據本身的業務作取捨。

4. 前端業務拓展

當咱們應用了Nodejs服務以後,能夠拓展的技術點有哪些,一下簡單列舉一些:

  1. 服務端渲染:提升首屏渲染時間,提高用戶體驗。
  2. 前端接口校驗:增長前端訪問後端接口,後端接口返回數據的安全性。
  3. 先後端分離,前端工程師的靈活性更加的高。

5. 技術升級帶來的收益

  1. 前端上線能夠實現小流量、灰度、發佈,能夠對線上流量作A/B測試,減小線上問題;
  2. 能夠定製化對部分用戶推進新功能;
  3. 加快首屏的渲染時間,提高用戶體驗;
  4. 多機房部署前端代碼,下降前端服務不可用的風險;
  5. 團隊成員技術能力的提高;

6. 最後

固然這種方案也不只僅是可使用Nodejs來作,也可使用其它語言。由於咱們公司已經有基於A/B測試的Nodejs-SDK。我這我就不具體介紹原理了。原理能夠參考百度百科。若是有問題須要一塊兒討論能夠留言或者是郵箱聯繫我:hpuhouzhiqiang@gmail.com

相關文章
相關標籤/搜索