第一是如果你 頻繁的Reload會有性能損耗;
第二個(gè)是 長時(shí)間處于Shutting down的狀態(tài), 如果連接里頭有長連接,舊的進(jìn)程會一直處于一個(gè)中間進(jìn)程,這個(gè)時(shí)間是不定的,就是說你不知道到底什么時(shí)候Reload真正完成;
第三是 進(jìn)程內(nèi)緩存失效, 我們會把數(shù)據(jù)庫的一些信息,一些代碼全部緩存進(jìn)本地,這樣緩存就全部失效了。
當(dāng)然前面三點(diǎn)也不是非常的嚴(yán)重,畢竟reload的操作不是特別的頻繁。
最后一點(diǎn)是 與設(shè)計(jì)初衷不符, 這也是我們最關(guān)心的一點(diǎn),它設(shè)計(jì)的初衷是做什么呢?就是方便運(yùn)維不去影響當(dāng)前的請求,就相當(dāng)于我們拿Docker做虛擬機(jī)用一樣走歪了,走歪了之后最后很可能會碰到很多奇怪的坑,所以當(dāng)時(shí)沒有用這個(gè)方案。
2. 內(nèi)部DNS方案

DNS的方案也是比較常用的,比如我把之前是一個(gè)IP地址的Server,現(xiàn)在改成一個(gè)域名,只要把它解析掉一批IP就好了,這個(gè)聽起來已經(jīng)很完美了,而且Consul本身支持DNS,我們也不用維護(hù)另外的DNS了,只要把這個(gè)ID換成域名就好了。
這樣做的話,我們感覺還不如做Reload,因?yàn)槭紫?多了一層DNS解析時(shí)間, 再怎么快都是需要解析時(shí)間的,第二個(gè)是 有DNS緩存, 這是最主要的原因,因?yàn)榫彺娴拇嬖?,沒辦法立即把一臺有問題的機(jī)器切掉,如果你要緩解這個(gè)問題,就要把緩存設(shè)得短一點(diǎn),但這樣解析次數(shù)就多了。還有一個(gè)就是 端口號會改變, 物理機(jī)一般我們會配置同一個(gè)端口,在Docker里面也可以這么做,但對于一些對網(wǎng)絡(luò)不是很敏感的應(yīng)用,比如說一些強(qiáng)CPU的應(yīng)用,我們會直接把容器的網(wǎng)絡(luò),用橋接的方式連接起來,而這時(shí)候端口是隨機(jī)分配的,可能每個(gè)容器分配的都不一樣,所以就不行。
那我們到底想要怎么樣呢? 我們想要的非常簡單,就是要通過HTTP接口,動(dòng)態(tài)修改Nginx的上游服務(wù)列表。 這樣的方案我們找了之后發(fā)現(xiàn)有一個(gè)現(xiàn)成的,叫ngx_http_dyups_module。
3. Ngx_http_dyups_module

它能干什么事情呢?可以通過GET接口查詢當(dāng)前的一些信息;POST可以更新上游;也能通過Ddelete刪除上游。

上圖是一個(gè)例子,這個(gè)例子有三個(gè)請求,也就是發(fā)了三個(gè)指令:
第一個(gè),給8080這個(gè)服務(wù)端口發(fā)了請求之后,發(fā)現(xiàn)后面根本就沒有任何的上游服務(wù),所以它就502了;
第二個(gè),通過一個(gè)Curl的請求把兩個(gè)服務(wù)地址給加進(jìn)來;
第三個(gè),重新訪問了一下,第三條指令跟第一條指令是一模一樣,因?yàn)榈诙l已經(jīng)把服務(wù)加進(jìn)來了,所以這是一個(gè)正常的輸出。
在這個(gè)過程里頭沒有任何的Reload的操作,也沒有改配置,它就完成了一個(gè)功能。
這個(gè)模塊寫得非常好,我們用了一段時(shí)間,但一段時(shí)間后把它下掉了,主要原因不是因?yàn)樗缓?,主要是我們結(jié)合了一些自身的情況,發(fā)現(xiàn)了一些問題:
第一, 導(dǎo)致依賴Nginx本身的負(fù)載均衡算法。 如果我們內(nèi)部用Ngx_lua寫得比較多,用了這個(gè)模塊之后,會導(dǎo)致我們非常依賴C模塊,也就是自身的一些負(fù)載均衡算法,我們有自己特有的需求,比如說本機(jī)優(yōu)先,就是優(yōu)先訪問本機(jī)的服務(wù),這樣聽起來比較奇怪的負(fù)載均衡,如果要做這些事情的話,我們就要改C代碼。
第二, 二次開發(fā)效率低, C的開發(fā)效率遠(yuǎn)不及Lua。
第三, 純lua的方案無法使用, 我們做這樣一個(gè)方案并不是說我云處理能用就行了,有一個(gè)項(xiàng)目能用就行了,做這個(gè)方案最好是其他一些項(xiàng)目都可以用。
造自己的輪子
基于以上這些原因,我們開始造自己的輪子。

這個(gè)輪子是這樣的,有四個(gè)部分:
第一個(gè)部分,是最基礎(chǔ)的nginx,我們希望用一些原生的指令和重試的策略;
第二就是lua的模塊;
第三個(gè)是lua_resty_checkups,這是我們lua版的管理模塊,實(shí)現(xiàn)了動(dòng)態(tài)的upstream管理,這個(gè)模塊實(shí)現(xiàn)了大概30%的功能,而且還有一些主動(dòng)的健康檢查功能,它的代碼量大概也就是1500左右,那C模塊估計(jì)至少有1萬行。