聊聊nginx平滑重新啟動和FPM平滑重新啟動

2022-03-10 13:00:26
本篇文章帶大家瞭解一下平滑重新啟動,詳細介紹一下nginx平滑重新啟動和FPM平滑重新啟動,希望能夠給大家提供幫助!

平滑重新啟動

GR是Graceful Restart(平滑重新啟動)的簡稱,是一種在協定重新啟動時保證轉發業務不中斷的機制。
GR機制的核心在於:當某裝置進行協定重新啟動時,能夠通知其周邊裝置在一定時間內將到該裝置的鄰居關係和路由保持穩定。在協定重新啟動完畢後,周邊裝置協助其進行資訊(包括支援GR的路由/MPLS相關協定所維護的各種拓撲、路由和對談資訊)同步,在儘量短的時間內使該裝置恢復到重新啟動前的狀態。在整個協定重新啟動過程中不會產生路由振盪,報文轉發路徑也沒有任何改變,整個系統可以不間斷地轉發資料。這個過程即稱為平滑重新啟動。

nginx平滑重新啟動

nginx程序分為master主程序和worker工作程序,nginx的平滑重新啟動通過訊號HUB控制。

0ad5774570f0acecd781efd944017ea.jpg

注:在POSIX相容的平臺上,SIGUSR1和SIGUSR2是傳送給一個程序的訊號,它表示了使用者定義的情況。

為了詳細分析nginx的平滑重新啟動過程,我們持續監控nginx程序變化。
傳送HUP訊號

kill -HUP `cat /home/git/nginx/logs/nginx.pid`

32de880788b49e2bab09de71b97759b.jpg

95b2574132403d0d7e33a32b70194ae.jpg

7f0b2c2e657ae0be2ac0d7c634a8d71.jpg

通過觀察,可以分析出大致的平滑重新啟動過程為:
1. master使用新設定 fork出n-1個worker及新master
2. 新worker處理新情求,舊worker執行完退出
3. master重新載入設定,期間使用新master接管服務
4. master載入設定完畢,新master切換為worker工作模式
平滑重新啟動完,master程序號並不會發生變化。

nginx平滑升級

HUP僅用於平滑重新啟動,載入設定等,如果要平滑升級nginx版本,重新載入編譯的二進位制檔案,需要藉助於USR2訊號。

1. 傳送USR2訊號

kill -USR2 `cat /home/git/nginx/logs/nginx.pid`

0f75284aede5d90d307458b071b4174.jpg

210c1db1969213752333832cd71c05b.jpg

觀察到nginx程序,fork出新master及worker,此時nginx.pid內容已經發生變化,並且在logs目錄下生成了nginx.pid.oldbin檔案,記錄舊master pid.

2. 向舊master傳送WINCH訊號,nginx woker會優雅地停止服務,即:停止接收新的請求,但是不會終止已經在處理的請求。一段時間後,舊nginx的所有worker程序全部退出,只剩下master程序,而使用者請求全部都由新的nginx程序處理。

kill -WINCH `cat /home/git/nginx/logs/nginx.pid.oldbin`

eb088238bc325e794efda24b678e844.jpg

3、向舊master傳送QUIT訊號,舊nginx程序完全退出,至此平滑升級完成。

kill -QUIT `cat /home/git/nginx/logs/nginx.pid.oldbin`

627f567cac1d81d2088256adb485538.jpg

FPM平滑重新啟動

FPM(FastCGI 程序管理器)用於替換 PHP FastCGI 的大部分附加功能,php5.3.3之後已經整合FPM,在./configure的時候帶 –enable-fpm引數即可開啟PHP-FPM。

FPM的平滑重新啟動需要通過USR2訊號控制,不過與nginx的平滑重新啟動過程有較大的不同。

kill -USR2 `cat /home/git/php/var/run/php-fpm.pid`

1c3133d36598e0555cd900d9af20106.jpg

通過持續觀察fpm程序可以看到,FPM平滑重新啟動,需要等子程序完全退出後,才會啟動新的master及子程序,隨後舊master退出。
使用strace進一步分析

f494282ba6d4d3feebffcb1fae8eedd.jpg

發現master通知所有子程序退出,包含正在處理請求的子程序。

為了進一步驗證這個結論,編寫一個伺服器端sleep指令碼

<?php
exec("sleep 5");
echo 'done';

用瀏覽器請求這個地址,並在此期間平滑重新啟動fpm,請求直接502了。
nginx錯誤紀錄檔:

[error] 29841#0: *1646 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 127.0.0.1, server: localhost, request: "GET /test.php HTTP/1.1", upstream: "fastcgi://127.0.0.1:9001", host: "localhost"

php bug#60961,也有對fpm無法優雅的實現平滑重新啟動的說明。
難道FPM這麼low?答案當時是no,實際上通過 process_control_timeout 引數可以實現我們的目標。

process_control_timeout

設定子程序接受主程序複用訊號的超時時間。可用單位:s(秒),m(分),h(小時)或者 d(天)。預設單位:s(秒)。預設值:0(關閉)。

原則上,php-fpm會選擇空閒的fastcgi程序去處理請求,在處理之前,php-fpm會給fastcgi傳送訊號,用來讓fastcgi程序準備好接受請求處理。但是fastcgi程序並不總是能夠處理請求,也就是不能總是響應該訊號(比如出現假死的情況),這時候就需要設定php-fpm留給fastcgi程序響應訊號的時間,如果超時了,php-fpm會想其他辦法(例如選擇其他fastcgi程序),這個就是process_control_timeout引數的作用。

這個引數預設是 0,也就是不生效,修改為10,重新驗證,502已經不會再出現。

結論:預設情況下,PHP-FPM 無法保證平滑的執行 reload 操作,必須設定一個合理的 process_control_timeout 才行,同時需要注意的是其值不能設定的過大,否則系統可能出現嚴重的請求堵塞問題。

推薦學習:《》

以上就是聊聊nginx平滑重新啟動和FPM平滑重新啟動的詳細內容,更多請關注TW511.COM其它相關文章!