如何利用Nginx為系統(tǒng)構(gòu)筑發(fā)布前的最后一道防線
背景
在項(xiàng)目發(fā)展的早期,為了簡(jiǎn)單方便,我們升級(jí)服務(wù)器端應(yīng)用,一般會(huì)先將應(yīng)用源碼或程序包上傳到服務(wù)器,然后再停掉老版本服務(wù),啟動(dòng)新版本服務(wù)。由于此時(shí),項(xiàng)目用戶少訪問(wèn)量小,這樣做通常不會(huì)有什么太大問(wèn)題。但后面隨著項(xiàng)目越來(lái)越大,用戶越來(lái)越多,再這樣做你會(huì)發(fā)現(xiàn)存在兩個(gè)明顯的問(wèn)題。
1、在新版本升級(jí)過(guò)程中,服務(wù)是暫時(shí)中斷的,在這期間,服務(wù)將不可使用。
2、如果新版本有BUG,升級(jí)失敗,回滾起來(lái)將非常麻煩,容易造成更長(zhǎng)時(shí)間的服務(wù)不可用。
為了解決上面這些問(wèn)題,人們研究出了很多發(fā)布策略,如藍(lán)綠發(fā)布、滾動(dòng)發(fā)布等,下面要講的灰度發(fā)布也是其中之一。
什么是灰度發(fā)布
灰度發(fā)布也叫金絲雀發(fā)布,其原理如下圖所示:
用文字描述即在灰度發(fā)布開始后,我們會(huì)先啟動(dòng)一個(gè)新版本應(yīng)用V2,但是此時(shí)并不直接將流量切過(guò)來(lái),而是先讓測(cè)試人員對(duì)新版本進(jìn)行線上測(cè)試。如果測(cè)試沒(méi)有問(wèn)題,那么就將少量的(如圖中的5%)用戶流量導(dǎo)入到新版本上,然后再對(duì)新版本做運(yùn)行狀態(tài)觀察,收集各種運(yùn)行時(shí)數(shù)據(jù)。當(dāng)確認(rèn)新版本運(yùn)行良好后,再逐步將更多的流量導(dǎo)入到新版本上。
在此期間,我們可以不斷地調(diào)整新舊兩個(gè)版本的運(yùn)行的服務(wù)器副本數(shù)量,以使得新版本能夠承受越來(lái)越大的流量壓力。當(dāng)最后我們將100%的流量都切換到新版本上后,就可以關(guān)閉剩下的老版本服務(wù),完成灰度發(fā)布。
另外,如果在灰度發(fā)布過(guò)程中發(fā)現(xiàn)新版本有問(wèn)題,我們可以立即將流量切回老版本上,這樣,可以將負(fù)面影響控制在最小范圍內(nèi)。
如何實(shí)現(xiàn)灰度發(fā)布
實(shí)現(xiàn)灰度發(fā)布有多種方式,但總結(jié)起來(lái)有三類
- 基于IP
- 基于COOKIE
- 基于權(quán)重
如下是利用nginx對(duì)這三類的實(shí)現(xiàn)。
1、基于IP
我們利用LUA,先獲取客戶端IP,然后通過(guò)判斷客戶端IP的類型,來(lái)判斷應(yīng)該選擇訪問(wèn)什么服務(wù)器。如果是客戶端IP為公司出口IP,則反向代理到@client;如果不是,則反向代理到@client_test。如下:
2、基于Cookie
我們先定義三個(gè)upstream,tts_v6、tts_v7和default,然后查詢Cookie鍵為version的值,如果該Cookie值為tts1,則轉(zhuǎn)發(fā)到tts_v6;如果該Cookie值為tts2,則轉(zhuǎn)發(fā)到tts_v7;如果該Cookie值既不是tts1,也不是tts2,則默認(rèn)走default所對(duì)應(yīng)的服務(wù)器。如下:
其中,192.168.3.81:5380所指向的服務(wù)器為運(yùn)行新功能的服務(wù)器。
3、基于權(quán)重
我們定義一個(gè)upstream,設(shè)置三個(gè)服務(wù)器IP,其權(quán)重分別為5,3,1。我們先把新功能部署在權(quán)重為1的服務(wù)器上,然后使用ip_hash進(jìn)行負(fù)載均衡。待權(quán)重為1的服務(wù)器運(yùn)行沒(méi)有問(wèn)題后,就將新功能部署到權(quán)重為3的服務(wù)器。如此重復(fù)操作,最后將新功能部署到所有服務(wù)器上。如下:
總結(jié)
灰度發(fā)布雖然操作復(fù)雜,但在一定程度上保證了系統(tǒng)的安全與穩(wěn)定。隨著項(xiàng)目的不斷發(fā)展,系統(tǒng)穩(wěn)定越來(lái)越比完善功能更加重要。從長(zhǎng)遠(yuǎn)來(lái)看,使用灰度發(fā)布利大于弊。