本篇文章給大家?guī)砹岁P(guān)于前端的相關(guān)知識,其中主要跟大家分享一個(gè)簡單的前端灰度系統(tǒng),并且介紹這個(gè)系統(tǒng)怎么寫的?感興趣的朋友下面一起來看一下吧,希望對大家有幫助。
(資料圖)
寫在前面的話
灰度這個(gè)概念,來自數(shù)字圖像領(lǐng)域,最初是描述黑白數(shù)字圖像的灰度值,范圍從 0到 255,0表示黑色,255表示白色,中間的數(shù)值表示不同程度的灰色。
灰度系統(tǒng)的誕生源于交叉學(xué)科的建設(shè),在互聯(lián)網(wǎng)上也不例外。對于一個(gè)軟件產(chǎn)品,在開發(fā)和發(fā)布的時(shí)候肯定希望用戶能夠順利的看到想讓其看到的內(nèi)容。但是,發(fā)布沒有一帆風(fēng)順的,如果在發(fā)布的某個(gè)環(huán)節(jié)出了問題,比如打錯(cuò)了鏡像或者由于部署環(huán)境不同觸發(fā)了隱藏的bug,導(dǎo)致用戶看到了錯(cuò)誤的頁面或者舊的頁面,這就出現(xiàn)了生產(chǎn)事故。為了避免這種情況出現(xiàn),借鑒數(shù)字圖像處理的理念,設(shè)計(jì)師們設(shè)計(jì)出了一種介于 0和 1之間的過渡系統(tǒng)的概念:讓系統(tǒng)可以預(yù)先發(fā)布,并設(shè)置可見范圍,就像朋友圈一樣,等到風(fēng)險(xiǎn)可控后,再對公眾可見。這就是灰度系統(tǒng)。
灰度系統(tǒng)版本的發(fā)布動作稱作 灰度發(fā)布,又名金絲雀發(fā)布,或者灰度測試,他是指在黑與白之間能夠平滑過渡的一種發(fā)布方式。在其上可以進(jìn)行A/B testing,即讓一部分用戶繼續(xù)用產(chǎn)品特性A,一部分用戶開始用產(chǎn)品特性B,如果用戶對B沒有什么反對意見,那么逐步擴(kuò)大范圍,把所有用戶都遷移到B上面來。(概念來自知乎)
對于前端領(lǐng)域,演進(jìn)到現(xiàn)在,灰度系統(tǒng)主要有如下幾點(diǎn)功能:
增量灰度:小的patch可以增量的添加在發(fā)布版本上,也可以通過開關(guān)一鍵關(guān)閉用戶灰度:增量和全量版本都可對不同群體或者某幾個(gè)特定的用戶進(jìn)行灰度可見版本回退:每一個(gè)版本都在灰度系統(tǒng)里可見,可以一鍵回退前端灰度系統(tǒng)工作流程圖如下:
sequenceDiagram前端項(xiàng)目-->灰度系統(tǒng): 部署階段前端項(xiàng)目->>灰度系統(tǒng): 1.CI 寫入打包資源前端項(xiàng)目->>灰度系統(tǒng): 2.CI 打包完成后更新資源狀態(tài)前端項(xiàng)目-->灰度系統(tǒng): 訪問階段前端項(xiàng)目->>灰度系統(tǒng): 1.頁面訪問,請求當(dāng)前登錄用戶對應(yīng)的資源版本灰度系統(tǒng)-->>前端項(xiàng)目: 2.從對應(yīng)版本的資源目錄返回前端資源
關(guān)于灰度資源優(yōu)先級的說明如下:
| 灰度策略 | 優(yōu)先級 |
|---|---|
| 未生效 | 低 |
| 生效 | 高 |
| 全量 | 一般 |
如此就起到了灰度的作用:全量表示所有人都可以看;生效表示只有在規(guī)則中的用戶才可以看到這部分增量更新,優(yōu)先級最高;未生效表示不灰度,優(yōu)先級最低。
先介紹一個(gè)要部署的前端項(xiàng)目(你可以根據(jù)自己的前端項(xiàng)目動態(tài)調(diào)整)。
本項(xiàng)目針對的前端項(xiàng)目是一個(gè)基于微服務(wù)架構(gòu)的項(xiàng)目,
下面是設(shè)計(jì)ER圖:
我們依此來分析:
該表用于存放所有子項(xiàng)目的信息,新建一個(gè)微服務(wù)子項(xiàng)目時(shí),會在這個(gè)表里新建一個(gè)條目,數(shù)據(jù)示意如下:
用于灰度系統(tǒng)登錄的用戶,擁有灰度權(quán)限的人才可以加入。
資源表存放項(xiàng)目在 CI 中寫入的 commit 信息和 build 完以后在服務(wù)器的存放位置,數(shù)據(jù)示意如下:
其中 branch是跑CI的分支,data存放打包資源目錄信息,一般結(jié)構(gòu)如下:
gitProjectId存放該產(chǎn)品在 gitlab 中的項(xiàng)目號, status表示構(gòu)建狀態(tài):0:構(gòu)建完成 1:部署完成 2:構(gòu)建失敗,3:部署失敗。
這里簡單提一下 CI 是如何寫入灰度系統(tǒng)數(shù)據(jù)庫的,過多詳情不做解釋,寫入數(shù)據(jù)庫方式很多,這只是其中一種實(shí)現(xiàn)方式。
首先在 CI build 環(huán)節(jié)往服務(wù)器寫入打包信息的 JSON:其中 build.sh 負(fù)責(zé)把傳入的參數(shù)寫到一個(gè) json 中。
在 CI 部署環(huán)節(jié),通過調(diào)用腳本創(chuàng)建資源:其中 run_gray.js:
const { ENV, file, branch, projectId, gitProjectId, user, commitMsg } = require("yargs").argv;axios({ url: URL, method: "POST", headers: { remoteUser: user }, data: { Action: "CreateResource", projectId, branch, commitMsg, gitProjectId, channel: Channel, data: fs.readFileSync(file, "utf8"), status: "0" }}).then(...)其中 status 的變化,在 CI 部署服務(wù)器完成后,追加一個(gè) UpdateResource動作即可:
if [[ $RetCode != 0 ]]; then curl "$STARK_URL" -X "POST" -H "remoteUser: ""$GITLAB_USER_NAME""" -H "Content-Type: application/json" -d "{"Action": "UpdateResource", "id": """$ResourceId""", "status": "2"}" > test.log && echo `cat test.log`; fi灰度策略是對灰度資源的調(diào)動配置。其設(shè)計(jì)如下:
其中,prijectId表示灰度的項(xiàng)目,resourceId表示使用的資源,rules配置了對應(yīng)的用戶或用戶組(看你怎么配置了,我這里只配置了單獨(dú)的 userId),status是灰度的狀態(tài),我設(shè)置了三種:
狀態(tài)生效表示是增量發(fā)布的意思。
到這里,數(shù)據(jù)庫設(shè)計(jì)就完畢了。
有了數(shù)據(jù)庫,還需要提供能夠操作數(shù)據(jù)庫的服務(wù),上邊創(chuàng)建資源的接口就是調(diào)用的灰度自己的API實(shí)現(xiàn)的。主要的API列表如下:
| 名稱 | 描述 |
|---|---|
| getResourcesByProjectId | 獲取單個(gè)產(chǎn)品下所有資源 |
| getResourcesById | 通過主鍵獲取資源 |
| createResource | 創(chuàng)建一個(gè)資源 |
| updateResource | 更新一個(gè)資源 |
| getIngressesByProjectId | 獲取單個(gè)產(chǎn)品下灰度策略任務(wù)列表 |
| getIngressById | 通過主鍵獲取單個(gè)灰度策略任務(wù)詳情 |
| createIngress | 創(chuàng)建一個(gè)策略 |
| updateIngress | 更新一個(gè)策略 |
剩余的接口有用戶處理的,有子項(xiàng)目管理的,這里不做詳述。除了上邊的必須的接口外,還有一個(gè)最重要的接口,那就是獲取當(dāng)前登錄用戶需要的資源版本的接口。在用戶訪問時(shí),需要首先調(diào)用灰度系統(tǒng)的這個(gè)接口來獲取資源地址,然后才能重定向到給該用戶看的頁面中去:
| 名稱 | 描述 | 接收參數(shù) | 輸出 |
|---|---|---|---|
| getConsoleVersion | 獲取當(dāng)前用的產(chǎn)品版本 | userId,products | resource鍵值對列表 |
getConsoleVersion接受兩個(gè)參數(shù),一個(gè)是當(dāng)前登錄的用戶 ID, 一個(gè)是當(dāng)前用戶訪問的微服務(wù)系統(tǒng)中所包含的產(chǎn)品列表。該接口做了如下幾步操作:
其中第三步處理相對繁瑣一些,比如說,一個(gè)資源有兩個(gè)起作用的灰度資源,一個(gè)是增量的,一個(gè)是全量的,這里應(yīng)該拿增量的版本,因?yàn)樗麅?yōu)先級更高。
獲取用戶版本的流程圖如下:
graph TD用戶登錄頁面 --> 獲取所有產(chǎn)品下的資源列表獲取所有產(chǎn)品下的資源列表 --> 根據(jù)灰度策略篩選資源中該用戶可用的部分 --> 返回產(chǎn)品維度的資源對象
最后返回的資源大概長這個(gè)樣子:
interface VersionResponse { [productId: number]: ResourceVersion;}interface ResourceVersion { files: string[]; config: ResourceConfig; dependencies: string[];}其中 files 就是 JSON 解析后的上述 data 信息的文件列表,因?yàn)榇虬蟮奈募?css和多個(gè)js。
至于這個(gè)后端使用什么語言,什么框架來寫,并不重要,重要的是一定要穩(wěn)定,他要掛掉了,用戶就進(jìn)不去系統(tǒng)了,容災(zāi)和容錯(cuò)要做好;如果是個(gè)客戶比較多的網(wǎng)站,并發(fā)分流也要考慮進(jìn)去。
前端頁面就隨便使用了一個(gè)前端框架搭了一下,選型不是重點(diǎn),組件庫能夠滿足要求就行:
登錄查看資源配置策略部署以后,實(shí)際運(yùn)行項(xiàng)目看看效果:
可以看到,在調(diào)用業(yè)務(wù)接口之前,優(yōu)先調(diào)用了 getConsoleVersion來獲取版本,其返回值是以產(chǎn)品為 key 的鍵值對:
這里拿到部署信息后,服務(wù)器要進(jìn)行下一步處理的。我這里是把它封裝到一個(gè)對象中,帶著參數(shù)傳給了微服務(wù)的 hook 去了,可以期待一下后續(xù)的手寫一個(gè)前端微服務(wù)的系列文章;如果你是單頁應(yīng)用,可能需要把工作重心放在 Nginx 的轉(zhuǎn)發(fā)上,通過灰度系統(tǒng)告知轉(zhuǎn)發(fā)策略后,Nginx負(fù)責(zé)來切換路由轉(zhuǎn)發(fā),可能只是改變一個(gè)路由變量。(你也可以參照我 nginx 相關(guān)文章),下面我簡單的給個(gè)示意圖:
graph TD灰度系統(tǒng)配置灰度策略 --> 告知Nginx資源地址 告知Nginx資源地址 --> Nginx服務(wù)器配置資源轉(zhuǎn)發(fā)
前端灰度系統(tǒng),其實(shí)就是一個(gè)后臺管理系統(tǒng)。他配置和管理了不同版本的前端部署資源和對應(yīng)的用戶策略,在需要的時(shí)候進(jìn)行配置。
接下來的文章我會配套性的講一下 Nginx和 Docker的前端入門使用,敬請期待!
推薦學(xué)習(xí):《web前端開發(fā)》
以上就是分享一個(gè)簡單的前端灰度系統(tǒng)的詳細(xì)內(nèi)容,更多請關(guān)注php中文網(wǎng)其它相關(guān)文章!
關(guān)鍵詞: