作者 劉維
這段時(shí)間在 Reddit 看到一個(gè)討論,為什么 NGINX 不支持熱加載?乍看之下很反常識(shí),作為世界第一大 Web 服務(wù)器,不支持熱加載?難道大家都在使用的 nginx -s reload 命令都用錯(cuò)了?帶著這個(gè)疑問,讓我們開始這次探索之旅,一起聊聊熱加載和 NGINX 的故事。
NGINX 相關(guān)介紹
NGINX 是一個(gè)跨平臺(tái)的開源 Web 服務(wù)器,使用 C 語言開發(fā)。據(jù)統(tǒng)計(jì),全世界流量最高的前 1000 名網(wǎng)站中,有超過 40% 的網(wǎng)站都在使用 NGINX 處理海量請(qǐng)求。
NGINX 有什么優(yōu)勢(shì),導(dǎo)致它從眾多的 Web 服務(wù)器中脫穎而出,并一直保持高使用量呢?
我覺得核心原因在于,NGINX 天生善于處理高并發(fā),能在高并發(fā)請(qǐng)求的同時(shí)保持高效的服務(wù)。相比于同時(shí)代的其他競(jìng)爭(zhēng)對(duì)手例如 Apache、Tomcat 等,其領(lǐng)先的事件驅(qū)動(dòng)型設(shè)計(jì)和全異步的網(wǎng)絡(luò) I/O 處理機(jī)制,以及極致的內(nèi)存分配管理等眾多優(yōu)秀設(shè)計(jì),將服務(wù)器硬件資源壓縮到了極致。使得 NGINX 成為高性能 Web 服務(wù)器的代名詞。
當(dāng)然,除此之外還有一些其他原因,比如:
高度模塊化的設(shè)計(jì),使得 NGINX 擁有無數(shù)個(gè)功能豐富的官方模塊和第三方拓展模塊。
最自由的 BSD 許可協(xié)議,使得無數(shù)開發(fā)者愿意為 NGINX 貢獻(xiàn)自己的想法。
支持熱加載,能保證 NGINX 提供 7x24h 不間斷的服務(wù)。
關(guān)于熱加載
大家期望的熱加載功能是什么樣的?我個(gè)人認(rèn)為,首先應(yīng)該是用戶端無感知的,在保證用戶請(qǐng)求正常和連接不斷的情況下,實(shí)現(xiàn)服務(wù)端或上游的動(dòng)態(tài)更新。
那什么情況下需要熱加載?在如今云原生時(shí)代下,微服務(wù)架構(gòu)盛行,越來越多的應(yīng)用場(chǎng)景有了更加頻繁的服務(wù)變更需求。包括反向代理域名上下線、上游地址變更、IP 黑白名單更新等,這些都和熱加載息息相關(guān)。
那么 NGINX 是如何實(shí)現(xiàn)熱加載的?
NGINX 熱加載的原理
執(zhí)行 nginx -s reload 熱加載命令,就等同于向 NGINX 的 master 進(jìn)程發(fā)送 HUP 信號(hào)。在 master 進(jìn)程收到 HUP 信號(hào)后,會(huì)依次打開新的監(jiān)聽端口,然后啟動(dòng)新的 worker 進(jìn)程。
此時(shí)會(huì)存在新舊兩套 worker 進(jìn)程,在新的 worker 進(jìn)程起來后,master 會(huì)向老的 worker 進(jìn)程發(fā)送 QUIT 信號(hào)進(jìn)行優(yōu)雅關(guān)閉。老的 worker 進(jìn)程收到 QUIT 信號(hào)后,會(huì)首先關(guān)閉監(jiān)聽句柄,此時(shí)新的連接就只會(huì)流進(jìn)到新的 worker 進(jìn)程中,老的 worker 進(jìn)程處理完當(dāng)前連接后就會(huì)結(jié)束進(jìn)程。
從原理上看,NGINX 的熱加載能很好地滿足我們的需求嗎?答案很可能是否定的,讓我們來看下 NGINX 的熱加載存在哪些問題。
NGINX 熱加載的缺陷
首先,NGINX 頻繁熱加載會(huì)造成連接不穩(wěn)定,增加丟失業(yè)務(wù)的可能性。
NGINX 在執(zhí)行 reload 指令時(shí),會(huì)在舊的 worker 進(jìn)程上處理已經(jīng)存在的連接,處理完連接上的當(dāng)前請(qǐng)求后,會(huì)主動(dòng)斷開連接。此時(shí)如果客戶端沒處理好,就可能會(huì)丟失業(yè)務(wù),這對(duì)于客戶端來說明顯就不是無感知的了。
其次,在某些場(chǎng)景下,舊進(jìn)程回收時(shí)間長,進(jìn)而影響正常業(yè)務(wù)。
比如代理 WebSocket 協(xié)議時(shí),由于 NGINX 不解析通訊幀,所以無法知道該請(qǐng)求是否為已處理完畢狀態(tài)。即使 worker 進(jìn)程收到來自 master 的退出指令,它也無法立刻退出,而是需要等到這些連接出現(xiàn)異常、超時(shí)或者某一端主動(dòng)斷開后,才能正常退出。
再比如 NGINX 做 TCP 層和 UDP 層的反向代理時(shí),它也沒法知道一個(gè)請(qǐng)求究竟要經(jīng)過多少次請(qǐng)求才算真正地結(jié)束。
這就導(dǎo)致舊 worker 進(jìn)程的回收時(shí)間特別長,尤其是在直播、新聞媒體活語音識(shí)別等行業(yè)。舊 worker 進(jìn)程的回收時(shí)間通常能達(dá)到半小時(shí)甚至更長,這時(shí)如果再頻繁 reload,將會(huì)導(dǎo)致 shutting down 進(jìn)程持續(xù)增加,最終甚至?xí)?dǎo)致 NGINX OOM,嚴(yán)重影響業(yè)務(wù)。
# 一直存在舊 worker 進(jìn)程: nobody 6246 6241 0 10:51 ? 0000 nginx: worker process nobody 6247 6241 0 10:51 ? 0000 nginx: worker process nobody 6247 6241 0 10:51 ? 0000 nginx: worker process nobody 6248 6241 0 10:51 ? 0000 nginx: worker process nobody 6249 6241 0 10:51 ? 0000 nginx: worker process nobody 7995 10419 0 10:30 ? 0037 nginx: worker process is shutting down <= here nobody 7995 10419 0 10:30 ? 0037 nginx: worker process is shutting down nobody 7996 10419 0 10:30 ? 0037 nginx: worker process is shutting down
從上述內(nèi)容可以看到,通過nginx -s reload方式支持的“熱加載”,雖然在以往的技術(shù)場(chǎng)景中夠用,但是在微服務(wù)和云原生迅速發(fā)展的今天,它已經(jīng)捉襟見肘且不合時(shí)宜。
如果你的業(yè)務(wù)變更頻率是每周或者每天,那么 NGINX 這種 reload 還是滿足你的需求的。但如果變更頻率是每小時(shí)、每分鐘呢?假設(shè)你有 100 個(gè) NGINX 服務(wù),每小時(shí) reload 一次的話,就要 reload 2400 次;如果每分鐘 reload 一次,就是 864 萬次。這顯然是無法接受的。
因此,我們需要一個(gè)不需要進(jìn)程替換的 reload 方案,在現(xiàn)有 NGINX 進(jìn)程內(nèi)可以直接完成內(nèi)容的更新和實(shí)時(shí)生效。
在內(nèi)存中直接生效的熱加載方案
在 Apache APISIX 誕生之初,就是希望來解決 NGINX 熱加載這個(gè)問題的。
Apache APISIX 是基于 NGINX + Lua 的技術(shù)棧,以 ETCD 作為配置中心實(shí)現(xiàn)的云原生、高性能、全動(dòng)態(tài)的微服務(wù) API 網(wǎng)關(guān),提供負(fù)載均衡、動(dòng)態(tài)上游、灰度發(fā)布、精細(xì)化路由、限流限速、服務(wù)降級(jí)、服務(wù)熔斷、身份認(rèn)證、可觀測(cè)性等數(shù)百項(xiàng)功能。
使用 APISIX 你不需要重啟服務(wù)就可以更新配置,這意味著修改上游、路由、插件時(shí)都不用重啟。既然是基于 NGINX,APISIX 又是如何擺脫 NGINX 的限制實(shí)現(xiàn)完美熱更新?我們先看下 APISIX 的架構(gòu)。

通過上述架構(gòu)圖可以看到,之所以 APISIX 能擺脫 NGINX 的限制是因?yàn)樗焉嫌蔚扰渲萌糠诺?APISIX Core 和 Plugin Runtime 中動(dòng)態(tài)指定。
以路由為例,NGINX 需要在配置文件內(nèi)進(jìn)行配置,每次更改都需要 reload 之后才能生效。而為了實(shí)現(xiàn)路由動(dòng)態(tài)配置,Apache APISIX 在 NGINX 配置文件內(nèi)配置了單個(gè) server,這個(gè) server 中只有一個(gè) location。我們把這個(gè) location 作為主入口,所有的請(qǐng)求都會(huì)經(jīng)過這個(gè) location,再由 APISIX Core 動(dòng)態(tài)指定具體上游。因此 Apache APISIX 的路由模塊支持在運(yùn)行時(shí)增減、修改和刪除路由,實(shí)現(xiàn)了動(dòng)態(tài)加載。所有的這些變化,對(duì)客戶端都零感知,沒有任何影響。
再來幾個(gè)典型場(chǎng)景的描述。
比如增加某個(gè)新域名的反向代理,在 APISIX 中只需創(chuàng)建上游,并添加新的路由即可,整個(gè)過程中不需要 NGINX 進(jìn)程有任何重啟。再比如插件系統(tǒng),APISIX 可以通過 ip-restriction 插件實(shí)現(xiàn) IP 黑白名單功能,這些能力的更新也是動(dòng)態(tài)方式,同樣不需要重啟服務(wù)。借助架構(gòu)內(nèi)的 ETCD,配置策略以增量方式實(shí)時(shí)推送,最終讓所有規(guī)則實(shí)時(shí)、動(dòng)態(tài)的生效,為用戶帶來極致體驗(yàn)。
總結(jié)
NGINX 的熱加載在某些場(chǎng)景下會(huì)長時(shí)間存在新舊兩套進(jìn)程,導(dǎo)致額外消耗資源,同時(shí)頻繁熱加載也會(huì)導(dǎo)致小概率業(yè)務(wù)丟失。面對(duì)當(dāng)下云原生和微服務(wù)的技術(shù)趨勢(shì)下, 服務(wù)變化更加的頻繁,控制 API 的策略也發(fā)生了變化,導(dǎo)致我們對(duì)熱加載的需求提出了新需求,NGINX 的熱加載已經(jīng)不能滿足實(shí)際業(yè)務(wù)需求。
現(xiàn)在是時(shí)候切換到更貼合云原生時(shí)代并且更完善的熱加載策略、性能表現(xiàn)卓越的 API 網(wǎng)關(guān)——Apache APISIX,從而享受動(dòng)態(tài)、統(tǒng)一管理等特性帶來的管理效率上的極大提升。
審核編輯:湯梓紅
-
Web
+關(guān)注
關(guān)注
2文章
1287瀏覽量
71393 -
服務(wù)器
+關(guān)注
關(guān)注
13文章
9793瀏覽量
87935 -
命令
+關(guān)注
關(guān)注
5文章
737瀏覽量
22874 -
nginx
+關(guān)注
關(guān)注
0文章
171瀏覽量
12591
原文標(biāo)題:為什么NGINX的reload命令不是熱加載?
文章出處:【微信號(hào):OSC開源社區(qū),微信公眾號(hào):OSC開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
Nginx和Apache的差異
Nginx配置終極指南

Nginx性能優(yōu)化終極指南

Nginx緩存配置詳解

深度解析Nginx Gzip指令:優(yōu)化網(wǎng)站性能與加速加載速度的關(guān)鍵工具
nginx+lua+redis實(shí)現(xiàn)灰度發(fā)布
Nginx日常運(yùn)維方法Linux版

詳解nginx中的正則表達(dá)式

使用lsof實(shí)現(xiàn)對(duì)linux文件的誤刪除恢復(fù)練習(xí)

nginx隱藏版本號(hào)與WEB服務(wù)器信息

nginx負(fù)載均衡配置介紹

nginx中的正則表達(dá)式和location路徑匹配指南

評(píng)論