Nginx的程式管理與過載原理

itbsl發表於2021-04-21

程式結構圖

Nginx是多程式結構,多程式結構設計是為了保證Nginx的高可用高可靠,包含:

  • master程式:父程式,負責worker程式的管理
  • worker程式:子程式,worker程式一般配置與伺服器CPU核數相同,worker程式用來處理具體請求。
  • cache程式:也是子程式,包括cache manager和cache loader程式,主要是反向代理做快取使用。

注:多程式相對於多執行緒之所以能夠保證高可用與高可靠是因為程式間地址空間是獨立的,程式間的任務不會相互影響,相對多執行緒更加耗費CPU資源。而多執行緒共享一個程式的地址空間,其中一個執行緒任務失敗會影響到其它執行緒任務。

圖3-1 Nginx程式結構圖

假設我們的Nginx服務的使用者是nginx,我們可以使用如下命令檢視當前執行的Nginx服務的master程式和worker程式,而且可以看到4個worker程式的父程式ID都是master的程式ID(1325)。

[root@master ~]# ps -ef | grep nginx | grep -v grep | grep -v php-fpm
root       1325      1  0 11:28 ?        00:00:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx      1332   1325  0 11:28 ?        00:00:00 nginx: worker process
nginx      1334   1325  0 11:28 ?        00:00:00 nginx: worker process
nginx      1335   1325  0 11:28 ?        00:00:00 nginx: worker process
nginx      1336   1325  0 11:28 ?        00:00:00 nginx: worker process

圖3-2 一個master程式與四個worker子程式

我們可以通過 lsof -i:nginx埠號 來檢視我們的master和worker程式。

[root@master ~]# lsof -i:80
COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx   1325  root    6u  IPv4  22282      0t0  TCP *:http (LISTEN)
nginx   1332 nginx    6u  IPv4  22282      0t0  TCP *:http (LISTEN)
nginx   1334 nginx    6u  IPv4  22282      0t0  TCP *:http (LISTEN)
nginx   1335 nginx    6u  IPv4  22282      0t0  TCP *:http (LISTEN)
nginx   1336 nginx    6u  IPv4  22282      0t0  TCP *:http (LISTEN)

訊號量管理

Linux的訊號量管理機制

訊號是程式間通訊方式之一,典型用法是:終端使用者輸入中斷命令,通過訊號機制停止一個程式的執行。

我們可以通過給程式傳送訊號來管理我們的程式,kill -l命令可以檢視linux支援的訊號量

linux訊號量

一共有64號訊號量,主要需要弄清如下幾個:

kill -1 $PID:(SIGHUP)重新載入程式,對於與終端脫離關係的守護程式,這個訊號用於通知它重新讀取配置檔案;

kill -2 $PID:(SIGINT)中斷(通Ctrl+C);

kill -3 $PID:(SIGQUIT)從鍵盤輸入的退出(ctrl-\);

kill -9 $PID:(SIGKILL)立即殺死程式,無論當前程式處於什麼狀態;

kill -10 $PID:(SIGUSR1)$USR1和$USR2都是留給使用者自定義的訊號量;

kill -12 $PID:($IGUSR2)

kill -15 $PID:(SIGTERM)正常停止一個程式;

kill -17 $PID:(SIGCHLD)父子程式通訊的訊號量,父程式可以fork()出很多子程式,子程式掛掉會給父程式傳送訊號;

kill 可將指定的資訊送至程式。預設的資訊為 SIGTERM(15),可將指定程式終止。若仍無法終止該程式,可使用 SIGKILL(9) 資訊嘗試強制刪除程式。程式或工作的編號可利用 ps 指令或 jobs 指令檢視。

kill -l # 檢視所有能夠支援的訊號
kill PID
# 殺死一個程式
kill 1024
# 殺死多個程式 程式號之間用空格隔開
kill 1024 2048
# kill -9 表示立即強制結束程式
kill -9 1024

注:Ctrl+C:停止終端中正在執行的程式,Ctrl+C可以比較有好地中止終端中正在執行的程式(程式)

利用訊號量管理Nginx程式

管理Nginx程式可以這些方式:master程式worker程式命令列

使用訊號量管理master和worker(不推薦使用傳送訊號量的方式來管理worker程式,worker程式應該交給master程式來管理和維護)。

Master程式

  • 監控worker程式
    • CHLD
  • 管理worker程式
  • 接收訊號
    • TERM、INT
    • QUIT
    • HUP
    • USR1
    • USR2
    • WINCH

示例:

通過kill命令殺死master程式

kill -s SIGTERM 1325

通過kill命令讓Nginx重新讀取檔案,這樣會關閉就得worker程式,生成新的worker程式,master程式(ID)依舊保持不變

kill -s SIGHUP 1325

Worker程式

  • 接收訊號
    • TERM、INT
    • QUIT
    • USR1
    • WINCH
  • 雖然可以,但是不推薦使用訊號量方式直接管理worker程式,worker程式應該交給master程式來管理和維護

示例:

使用kill命令殺死一個worker程式,這樣會殺死一個worker程式,linux會殺掉的worker程式的父程式(master程式)傳送SIGCHLD訊號量,所以master程式監測到我們某一個子程式可能出了問題,會啟動一個新的worker程式,維護worker程式的數量。

kill -s SIGTERM 1332

命令列

  • reload:HUP
  • reopen:USR2
  • stop:TERM
  • quit:QUIT

可以使用nginx -h檢視幫助命令

[itbsl@master ~]$ nginx -h
nginx version: nginx/1.18.0
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]

Options:
  -?,-h         : this help
  -v            : show version and exit
  -V            : show version and configure options then exit
  -t            : test configuration and exit
  -T            : test configuration, dump it and exit
  -q            : suppress non-error messages during configuration testing
  -s signal     : send signal to a master process: stop, quit, reopen, reload
  -p prefix     : set prefix path (default: /usr/local/nginx-1.18.0/)
  -c filename   : set configuration file (default: conf/nginx.conf)
  -g directives : set global directives out of configuration file

引數說明:

  • -?,-h:檢視幫助
  • -v:檢視Nginx版本
  • -V:檢視Nginx版本和編譯選項
  • -t:檢查配置檔案語法是否正確
  • -T:檢查配置檔案語法是否正確,並列印
  • -q:在檢查配置檔案時不顯示非錯誤訊息
  • -s:給master程式傳送訊號,可以傳送:stop、quit、reopen、reload
  • -c:指定配置檔案
  • -g:設定配置檔案之外的全域性指令

配置檔案過載原理

我們知道了可以通過給nginx的master程式傳送SIGHUP訊號,或者使用nginx -s reload命令來達到重新載入配置檔案,從而使nginx平滑升級。那我們執行這樣一個命令之後,對nginx本身來說背後發生了什麼事情呢,它是如何保證新老請求如何平滑過渡的?

reload過載配置檔案的流程

  1. 向master程式傳送HUP訊號(reload命令)
  2. master程式檢查配置語法是否正確
  3. master程式開啟監聽埠(在修改配置檔案的埠情況下,可能)
  4. master程式使用新的配置檔案啟動新的worker子程式
  5. master程式向老的worker子程式傳送QUIT訊號
  6. 舊的worker程式關閉監聽控制程式碼,處理完當前連線後關閉程式

如果用圖示來描述的話大概如下圖所示

nginx -s reload

圖示解析:

1.左邊綠色的狀態是執行nginx -s reload命令之前的狀態,按照我個人主機的配置時一個master程式和4個worker子程式。

2.為了模擬執行nginx -s reload命令後原來的worker程式會處理完請求後再被殺掉,我模擬一個需要很久才能處理完任務並響應的介面,是的,我在程式碼裡sleep 15秒,也就是說這個介面響應需要15秒,時間弄長點方便我們來觀察中間態,注意,在執行reload命令前請求該介面

<?php
    sleep(15);
    echo json_encode(['msg' => 'hello world']);die();

3.我們已經知道了master程式會把任務交給worker子程式處理,目前只有一個任務,所以當前只需要一個worker程式需要處理任務。

4.執行reload命令,master程式會建立4個(與你配置有關)新的worker程式(我上圖中的黃色worker程式),關閉掉舊的空閒worker程式(綠色worker程式),而正在處理請求的舊worker程式不會立即關閉,而是會等請求處理完畢就關閉。

5.剩下的最後一箇舊worker程式任務處理完畢也被關掉,最後剩下的都是使用新nginx.conf配置產生的新worker程式,可以看下面的這張圖,那個處於is shutting down的舊worker程式就是因為處理上面sleep 15秒的任務介面還沒處理完畢,所以依然能夠被看到。

原創文章:轉載請註明原文連結:https://www.cnblogs.com/itbsl/p/14684211.html。

如果文章對您有幫助,請點選推薦鼓勵我,您的推薦是我更新文章的動力,感謝。

相關文章