基于Nginx實現一個灰度上線系統的示例代碼
軟件開發一般不會上來就是最終版本,而是會一個版本一個版本的迭代。
新版本上線前都會經過測試,但就算這樣,也不能保證上線了不出問題。
所以,在公司里上線新版本代碼一般都是通過灰度系統。
灰度系統可以把流量劃分成多份,一份走新版本代碼,一份走老版本代碼。
而且灰度系統支持設置流量的比例,比如可以把走新版本代碼的流程設置為 5%,沒啥問題再放到 10%,50%,最后放到 100% 全量。
這樣可以把出現問題的影響降到最低。
不然一上來就全量,萬一出了線上問題,那就是大事故。
而且灰度系統不止這一個用途,比如產品不確定某些改動是不是要的,就要做 AB 實驗,也就是要把流量分成兩份,一份走 A 版本代碼,一份走 B 版本代碼。
那這樣的灰度系統是怎么實現的呢?
其實很多都是用 nginx 實現的。
nginx 是一個反向代理的服務,用戶請求發給它,由它轉發給具體的應用服務器。
這一層也叫做網關層。
由它負責轉發請求給應用服務器,那自然就可以在這里控制流量的分配,哪些流量走版本 A,哪些流量走版本 B。
下面我們實現一下:
首先,我們準備兩個版本的代碼。
這里創建個 nest 項目:
npx nest new gray_test -p npm把 nest 服務跑起來:
npm run start瀏覽器訪問下:
看到 hello world 代表 nest 服務跑起來了。
然后改下 AppService:
修改下端口:
然后再 npm run start:
瀏覽器訪問下:
現在我們就有了兩個版本的 nest 代碼。
接下來的問題是,如何用 nginx 實現灰度,讓一部分請求走一個版本的代碼,一部分請求走另一個版本呢?
我們先跑一個 nginx 服務。
docker desktop 搜索 nginx 鏡像(這步需要科學上網),點擊 run:
設置容器名為 gray1,端口映射宿主機的 82 到容器內的 80
現在訪問 http://localhost:82 就可以看到 nginx 頁面了:
我們要修改下配置文件,把它復制出來:
docker cp gray1:/etc/nginx/conf.d ~/nginx-config然后編輯下這個 default.conf
添加這么一行配置:
location ^~ /api { rewrite ^/api/(.*)$ /$1 break; proxy_pass http://192.168.1.6:3001;}這行就是加了一個路由,把 /api/ 開頭的請求轉發給 http://宿主機IP:3001 這個服務。
用 rewrite 把 url 重寫了,比如 /api/xxx 變成了 /xxx。
然后我們重新跑個 nginx 容器:
容器名為 gray2,端口映射 83 到容器內的 80。
指定數據卷,掛載本地的 ~/nginx-config 目錄到容器內的 /etc/nginx/conf.d 目錄。
點擊 run。
然后看下 files 部分:
可以看到容器內的 /etc/nginx/conf.d 目錄標識為了 mounted。
點開看看:
這就是本地的那個文件。
我們在本地改一下試試:
容器內也同樣修改了。
在容器內修改這個文件,本地同樣也會修改。
也就是說掛載數據卷之后,容器內的這個目錄就是本地目錄,是同一份。
然后我們訪問下 http://localhost:83/api/ 看看:
nest 服務訪問成功了。
現在我們不是直接訪問 nest 服務了,而是經歷了一層 nginx 反向代理或者說網關層。
自然,我們可以在這一層實現流量控制的功能。
前面我們講負載均衡的時候,是這么配的:
默認會輪詢把請求發給 upstream 下的 server。
現在需要有多組 upstream:
upstream version1.0_server { server 192.168.1.6:3000;}upstream version2.0_server { server 192.168.1.6:3001;}upstream default { server 192.168.1.6:3000;}有版本 1.0 的、版本 2.0 的,默認的 server 列表。
然后需要根據某個條件來區分轉發給哪個服務。
我們這里根據 cookie 來區分:
set $group 'default';if ($http_cookie ~* 'version=1.0'){ set $group version1.0_server;}if ($http_cookie ~* 'version=2.0'){ set $group version2.0_server;}location ^~ /api { rewrite ^/api/(.*)$ /$1 break; proxy_pass http://$group;}如果包含 version=1.0 的 cookie,那就走 version1.0_server 的服務,有 version=2.0 的 cookie 就走 version2.0_server 的服務,否則,走默認的。
這樣就實現了流量的劃分,也就是灰度的功能。
然后我們重新跑下容器:
這時候,你訪問 http://localhost:83/api/ 走到的就是默認的版本。
然后帶上 version=2.0 的 cookie,走到的就是另一個版本的代碼:
這樣,我們就實現了灰度的功能。
但現在還有一個問題:
什么時候設置的這個 cookie 呢?
比如我想實現 80% 的流量走版本 1.0,20% 的流量走版本 2.0
其實公司內部一般都有灰度配置系統,可以配置不同的版本的比例,然后流量經過這個系統之后,就會返回 Set-Cookie 的 header,里面按照比例來分別設置不同的 cookie。
比如隨機數載 0 到 0.2 之間,就設置 version=2.0 的 cookie,否則,設置 version=1.0 的 cookie。
這也叫做流量染色。
完整的灰度流程是這樣的:
第一次請求的時候,會按照設定的比例隨機對流量染色,也就是設置不同 cookie。
再次訪問的時候會根據 cookie 來走到不同版本的代碼。
這就實現了灰度功能,可以用來做 5% 10% 50% 100% 這樣逐步上線的灰度上線機制。
也可以用來做產品的 AB 實驗。
公司里都會用這樣的灰度系統。
總結新版本代碼的上線基本都會用灰度系統,可以逐步放量的方式來保證上線過程不會出大問題,也可以用來做產品 AB 實驗。
我們可以用 nginx 實現這樣的功能。
nginx 有反向代理的功能,可以轉發請求到應用服務器,也叫做網關層。
我們可以在這一層根據 cookie 里的 version 字段來決定轉發請求到哪個服務。
在這之前,還需要按照比例來給流量染色,也就是返回不同的 cookie。
不管灰度系統做的有多復雜,底層也就是流量染色、根據標記轉發流量這兩部分,我們完全可以自己實現一個。
到此這篇關于基于Nginx實現一個灰度上線系統的示例代碼的文章就介紹到這了,更多相關Nginx灰度上線系統內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!