nginx信號(hào)集怎么理解

本篇內(nèi)容主要講解“nginx信號(hào)集怎么理解”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“nginx信號(hào)集怎么理解”吧!

創(chuàng)新互聯(lián)建站主要從事網(wǎng)站建設(shè)、成都網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)阿瓦提,10余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來(lái)電咨詢建站服務(wù):13518219792

前言

之前工作時(shí)候,一臺(tái)引流測(cè)試機(jī)器的一個(gè) ngx_lua 服務(wù)突然出現(xiàn)了一些 HTTP/500 響應(yīng),從錯(cuò)誤日志打印的堆棧來(lái)看,是不久前新發(fā)布的版本里添加的一個(gè) Lua table 不存在,而有代碼向其進(jìn)行索引導(dǎo)致的。這令人百思不得其解,如果是版本回退導(dǎo)致的,那么為什么使用這個(gè) Lua table 的代碼沒(méi)有被回退,偏偏定義這個(gè) table 的代碼被回退了呢?

經(jīng)過(guò)排查發(fā)現(xiàn),當(dāng)時(shí) nginx 剛剛完成熱更新操作,舊的 master 進(jìn)程還存在,因?yàn)橐獪?zhǔn)備機(jī)器重啟,先切掉了引流流量(但有些請(qǐng)求還在),同時(shí)系統(tǒng)觸發(fā)了 nginx -s stop,這才導(dǎo)致了這個(gè)問(wèn)題。

場(chǎng)景復(fù)現(xiàn)

下面我將使用一個(gè)原生的 nginx,在我的安裝了 fedora26 的虛擬機(jī)上復(fù)現(xiàn)這個(gè)過(guò)程,我使用的 nginx 版本是目前最新的 1.13.4

首先啟動(dòng) nginx

nginx信號(hào)集怎么理解

可以看到 master 和 worker 都已經(jīng)在運(yùn)行。

接著我們向 master 發(fā)送一個(gè) SIGUSR2 信號(hào),當(dāng) nginx 核心收到這個(gè)信號(hào)后,就會(huì)觸發(fā)熱更新。

nginx信號(hào)集怎么理解

可以看到新的 master 和該 master fork 出來(lái)的 worker 已經(jīng)在運(yùn)行了,此時(shí)我們接著向舊 master 發(fā)送一個(gè) SIGWINCH 信號(hào),舊 master 收到這個(gè)信號(hào)后,會(huì)向它的 worker 發(fā)送 SIGQUIT,于是舊 master 的 worker 進(jìn)程就會(huì)退出:

nginx信號(hào)集怎么理解

此時(shí)只剩下舊的 master,新的 master 和新 master 的 worker 在運(yùn)行,這和當(dāng)時(shí)線上運(yùn)行的情況類似。

接著我們使用 stop 命令:

nginx信號(hào)集怎么理解

我們會(huì)發(fā)現(xiàn),新的 master 和它的 worker 都已經(jīng)退出,而舊的 master 還在運(yùn)行,并產(chǎn)生了 worker 出來(lái)。這就是當(dāng)時(shí)線上的情況了。

事實(shí)上,這個(gè)現(xiàn)象和 nginx 自身的設(shè)計(jì)有關(guān):當(dāng)舊的 master 準(zhǔn)備產(chǎn)生 fork 新的 master 之前,它會(huì)把 nginx.pid 這個(gè)文件重命名為 nginx.pid.oldbin,然后再由 fork 出來(lái)的新的 master 去創(chuàng)建新的 nginx.pid,這個(gè)文件將會(huì)記錄新 master 的 pid。nginx 認(rèn)為熱更新完成之后,舊 master 的使命幾乎已經(jīng)結(jié)束,之后它隨時(shí)會(huì)退出,因此之后的操作都應(yīng)該由新 master 接管。當(dāng)然,在舊 master 沒(méi)有退出的情況下通過(guò)向新 master 發(fā)送 SIGUSR2 企圖再次熱更新是無(wú)效的,新 master 只會(huì)忽略掉這個(gè)信號(hào)然后繼續(xù)它自己的工作。

問(wèn)題分析

更不巧的是,我們上面提到的這個(gè) Lua table,定義它的 Lua 文件早在運(yùn)行 init_by_lua 這個(gè) hook 的時(shí)候,就已經(jīng)被 LuaJIT 加載到內(nèi)存并編譯成字節(jié)碼了,那么顯然舊的 master 必然沒(méi)有這個(gè) Lua table,因?yàn)樗虞d那部分 Lua 代碼是舊版本的。

而索引該 table 的 Lua 代碼并沒(méi)有在 init_by_lua 的時(shí)候使用到,這些代碼都是在 worker 進(jìn)程里被加載起來(lái)的,這時(shí)候項(xiàng)目目錄里的代碼都是最新的,所以 worker 進(jìn)程加載的都是最新的代碼,如果這些 worker 進(jìn)程處理到相關(guān)的請(qǐng)求,就會(huì)出現(xiàn) Lua 運(yùn)行時(shí)錯(cuò)誤,外部表現(xiàn)則是對(duì)應(yīng)的 HTTP 500。

吸收了這個(gè)教訓(xùn)之后,我們需要更加合理地關(guān)閉我們的 nginx 服務(wù)。 所以一個(gè)更加合理的 nginx 服務(wù)啟動(dòng)關(guān)閉腳本是必需的,網(wǎng)上流傳的一些腳本并沒(méi)有對(duì)這個(gè)現(xiàn)象做處理,我們更應(yīng)該參考 NGINX 官方提供的腳本。

nginx信號(hào)集怎么理解

這段代碼引自 NGINX 官方的 /etc/init.d/nginx 。

nginx 信號(hào)集

接下來(lái)我們來(lái)全面梳理下 nginx 信號(hào)集,這里不會(huì)涉及到源碼細(xì)節(jié),感興趣的同學(xué)可以自行閱讀相關(guān)源碼。

我們有兩種方式來(lái)向 master 進(jìn)程發(fā)送信號(hào),一種是通過(guò) nginx -s signal 來(lái)操作,另一種是通過(guò) kill 命令手動(dòng)發(fā)送。

第一種方式的原理是,產(chǎn)生一個(gè)新進(jìn)程,該進(jìn)程通過(guò) nginx.pid 文件得到 master 進(jìn)程的 pid,然后把對(duì)應(yīng)的信號(hào)發(fā)送到 master,之后退出,這種進(jìn)程被稱為 signaller。

第二種方式要求我們了解 nginx -s signal 到真實(shí)信號(hào)的映射。下表是它們的映射關(guān)系:

operation signal reload SIGHUP reopen SIGUSR1 stop SIGTERM quit SIGQUIT hot update SIGUSR2 & SIGWINCH & SIGQUIT stop vs quit

stop 發(fā)送 SIGTERM 信號(hào),表示要求強(qiáng)制退出,quit 發(fā)送 SIGQUIT,表示優(yōu)雅地退出。 具體區(qū)別在于,worker 進(jìn)程在收到 SIGQUIT 消息(注意不是直接發(fā)送信號(hào),所以這里用消息替代)后,會(huì)關(guān)閉監(jiān)聽(tīng)的套接字,關(guān)閉當(dāng)前空閑的連接(可以被搶占的連接),然后提前處理所有的定時(shí)器事件,最后退出。沒(méi)有特殊情況,都應(yīng)該使用 quit 而不是 stop。

reload

master 進(jìn)程收到 SIGHUP 后,會(huì)重新進(jìn)行配置文件解析、共享內(nèi)存申請(qǐng),等一系列其他的工作,然后產(chǎn)生一批新的 worker 進(jìn)程,最后向舊的 worker 進(jìn)程發(fā)送 SIGQUIT 對(duì)應(yīng)的消息,最終無(wú)縫實(shí)現(xiàn)了重啟操作。

reopen

master 進(jìn)程收到 SIGUSR1 后,會(huì)重新打開(kāi)所有已經(jīng)打開(kāi)的文件(比如日志),然后向每個(gè) worker 進(jìn)程發(fā)送 SIGUSR1 信息,worker 進(jìn)程收到信號(hào)后,會(huì)執(zhí)行同樣的操作。reopen 可用于日志切割,比如 NGINX 官方就提供了一個(gè)方案:

nginx信號(hào)集怎么理解

這里 sleep 1 是必須的,因?yàn)樵?master 進(jìn)程向 worker 進(jìn)程發(fā)送 SIGUSR1 消息到 worker 進(jìn)程真正重新打開(kāi) access.log 之間,有一段時(shí)間窗口,此時(shí) worker 進(jìn)程還是向文件 access.log.0 里寫(xiě)入日志的。通過(guò) sleep 1s,保證了 access.log.0 日志信息的完整性(如果沒(méi)有 sleep 而直接進(jìn)行壓縮,很有可能出現(xiàn)日志丟失的情況)。

hot update

某些時(shí)候我們需要進(jìn)行二進(jìn)制熱更新,nginx 在設(shè)計(jì)的時(shí)候就包含了這種功能,不過(guò)無(wú)法通過(guò) nginx 提供的命令行完成,我們需要手動(dòng)發(fā)送信號(hào)。

通過(guò)上面的問(wèn)題復(fù)現(xiàn),大家應(yīng)該已經(jīng)了解到如何進(jìn)行熱更新了,我們首先需要給當(dāng)前的 master 進(jìn)程發(fā)送 SIGUSR2,之后 master 會(huì)重命名 nginx.pid 到 nginx.pid.oldbin,然后 fork 一個(gè)新的進(jìn)程,新進(jìn)程會(huì)通過(guò) execve 這個(gè)系統(tǒng)調(diào)用,使用新的 nginx ELF 文件替換當(dāng)前的進(jìn)程映像,成為新的 master 進(jìn)程。新 master 進(jìn)程起來(lái)之后,就會(huì)進(jìn)行配置文件解析等操作,然后 fork 出新的 worker 進(jìn)程開(kāi)始工作。

接著我們向舊的 master 發(fā)送 SIGWINCH 信號(hào),然后舊的 master 進(jìn)程則會(huì)向它的 worker 進(jìn)程發(fā)送 SIGQUIT 信息,從而使得 worker 進(jìn)程退出。向 master 進(jìn)程發(fā)送 SIGWINCH 和 SIGQUIT 都會(huì)使得 worker 進(jìn)程退出,但是前者不會(huì)使得 master 進(jìn)程也退出。

最后,如果我們覺(jué)得舊的 master 進(jìn)程使命完成,就可以向它發(fā)送 SIGQUIT 信號(hào),讓其退出了。

worker 進(jìn)程如何處理來(lái)自 master 的信號(hào)消息

實(shí)際上,master 進(jìn)程再向 worker 進(jìn)程通訊,不是使用 kill 函數(shù),而是使用了通過(guò)管道實(shí)現(xiàn)的 nginx channel,master 進(jìn)程向管道一端寫(xiě)入信息(比如信號(hào)信息),worker 進(jìn)程則從另外一端收取信息,nginx channel 事件,在 worker 進(jìn)程剛剛起來(lái)的時(shí)候,就被加入事件調(diào)度器中(比如 epoll,kqueue),所以當(dāng)有數(shù)據(jù)從 master 發(fā)來(lái)時(shí),即可被事件調(diào)度器通知到。

nginx 這么設(shè)計(jì)是有理由的,作為一個(gè)優(yōu)秀的反向代理服務(wù)器,nginx 追求的就是極致的高性能,而 signal handler 會(huì)中斷 worker 進(jìn)程的運(yùn)行,使得所有的事件都被暫停一個(gè)時(shí)間窗口,這對(duì)性能是有一定損失的。

很多人可能會(huì)認(rèn)為當(dāng) master 進(jìn)程向 worker 進(jìn)程發(fā)送信息之后,worker 進(jìn)程立刻會(huì)有對(duì)應(yīng)操作回應(yīng),然而 worker 進(jìn)程是非常繁忙的,它不斷地處理著網(wǎng)絡(luò)事件和定時(shí)器事件,當(dāng)調(diào)用 nginx channel 事件的 handler 之后,nginx 僅僅只是處理了一些標(biāo)志位。真正執(zhí)行這些動(dòng)作是在一輪事件調(diào)度完成之后。所以這之間存在一個(gè)時(shí)間窗口,尤其是業(yè)務(wù)復(fù)雜且流量巨大的時(shí)候,這個(gè)窗口就有可能被放大,這也就是為什么 NGINX 官方提供的日志切割方案里要求 sleep 1s 的原因。

當(dāng)然,我們也可以繞過(guò) master 進(jìn)程,直接向 worker 進(jìn)程發(fā)送信號(hào),worker 可以處理的信號(hào)有

signal effect SIGINT 強(qiáng)制退出 SIGTERM 強(qiáng)制退出 SIGQUIT 優(yōu)雅退出 SIGUSR1 重新打開(kāi)文件

到此,相信大家對(duì)“nginx信號(hào)集怎么理解”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

網(wǎng)站標(biāo)題:nginx信號(hào)集怎么理解
文章URL:http://bm7419.com/article20/iiheco.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站策劃、網(wǎng)站營(yíng)銷標(biāo)簽優(yōu)化、品牌網(wǎng)站制作、搜索引擎優(yōu)化、移動(dòng)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

小程序開(kāi)發(fā)