Nginx R31 doc-17-debugging 除錯

老马啸西风發表於2024-05-29

前言

大家好,我是老馬。很高興遇到你。

我們為 java 開發者實現了 java 版本的 nginx

https://github.com/houbb/nginx4j

如果你想知道 servlet 如何處理的,可以參考我的另一個專案:

手寫從零實現簡易版 tomcat minicat

手寫 nginx 系列

如果你對 nginx 原理感興趣,可以閱讀:

從零手寫實現 nginx-01-為什麼不能有 java 版本的 nginx?

從零手寫實現 nginx-02-nginx 的核心能力

從零手寫實現 nginx-03-nginx 基於 Netty 實現

從零手寫實現 nginx-04-基於 netty http 出入參最佳化處理

從零手寫實現 nginx-05-MIME型別(Multipurpose Internet Mail Extensions,多用途網際網路郵件擴充套件型別)

從零手寫實現 nginx-06-資料夾自動索引

從零手寫實現 nginx-07-大檔案下載

從零手寫實現 nginx-08-範圍查詢

從零手寫實現 nginx-09-檔案壓縮

從零手寫實現 nginx-10-sendfile 零複製

從零手寫實現 nginx-11-file+range 合併

從零手寫實現 nginx-12-keep-alive 連線複用

NGINX 除錯

透過除錯二進位制檔案、除錯日誌和核心轉儲來排除 NGINX 或 NGINX Plus 部署中的問題並追蹤錯誤。

介紹

除錯幫助您在程式程式碼出現問題時識別錯誤。它通常用於開發或測試第三方或實驗性模組。

NGINX 除錯功能包括除錯日誌和建立核心轉儲檔案以及進一步的回溯。

配置 NGINX 二進位制檔案進行除錯

首先,您需要在 NGINX 二進位制檔案中啟用除錯。NGINX Plus 已經為您提供了 nginx-debug 二進位制檔案,而 NGINX Open Source 需要重新編譯。

配置 NGINX Plus 二進位制檔案

從版本 8 開始,NGINX Plus 與標準二進位制檔案一起提供 nginx-debug 二進位制檔案。要在 NGINX Plus 中啟用除錯,您需要從 nginx 切換到 nginx-debug 二進位制檔案。開啟終端並執行以下命令:

service nginx stop && service nginx-debug start

完成後,在配置檔案中啟用除錯日誌。

編譯 NGINX Open Source 二進位制檔案

要在 NGINX Open Source 中啟用除錯,您需要使用 configure 指令碼中指定的 --with-debug 標誌重新編譯它。

要編譯支援除錯的 NGINX Open Source:

  1. 下載並解壓 NGINX 原始檔,轉到原始檔所在的目錄。參見下載原始碼
  2. 獲取 NGINX 配置引數列表。執行命令:
nginx -V 2>&1 | grep arguments
  1. 將 --with-debug 選項新增到 configure 命令列表中並執行 configure 指令碼:
./configure --with-debug <其他 configure 引數>
  1. 編譯和安裝 NGINX:
sudo make
sudo make install
  1. 重新啟動 NGINX。

NGINX 和除錯符號

除錯符號有助於獲取用於除錯的附加資訊,例如函式、變數、資料結構、原始檔和行號資訊。

NGINX 預設使用“-g”標誌編譯,其中包含除錯符號。

但是,如果在執行回溯時出現“沒有可用的符號表資訊”錯誤,則表示缺少除錯符號,您需要重新編譯 NGINX 並支援除錯符號。

確切的編譯器標誌取決於編譯器。例如,對於 GCC 編譯器系統:

  • 使用“-g”標誌包含除錯符號
  • 使用“-O0”標誌禁用編譯器最佳化,使偵錯程式輸出更易於理解:
./configure --with-debug --with-cc-opt='-O0 -g' ...

在 NGINX 配置中啟用除錯日誌

除錯日誌記錄錯誤和與除錯相關的任何資訊,預設情況下是禁用的。要啟用它,請確保 NGINX 已編譯支援除錯(參見“為除錯配置 NGINX 二進位制檔案”),然後在 NGINX 配置檔案中使用 error_log 指令的 debug 引數啟用它。除錯日誌可以寫入檔案、記憶體中的分配緩衝區、標準錯誤輸出或 syslog。

建議在 NGINX 配置的“main”級別上啟用除錯日誌,以獲得正在進行的完整情況。

將除錯日誌寫入檔案

將除錯日誌寫入檔案可能會在高負載下降低效能。還要注意,檔案可能會變得非常大,快速消耗磁碟空間。為減少負面影響,您可以配置除錯日誌寫入記憶體緩衝區,或為特定 IP 地址設定除錯日誌。有關詳細資訊,請參閱“將除錯日誌寫入記憶體”和“選定 IP 的除錯日誌”。

要啟用將除錯日誌寫入檔案:

  1. 確保您的 NGINX 配置了 --with-debug 配置選項。執行命令並檢查輸出是否包含 --with-debug 行:

    nginx -V 2>&1 | grep -- '--with-debug'
    
  2. 開啟 NGINX 配置檔案:

    sudo vi /etc/nginx/nginx.conf
    
  3. 查詢 error_log 指令,預設情況下位於 main 上下文中,並將日誌級別更改為 debug。如果需要,更改日誌檔案的路徑:

    error_log  /var/log/nginx/error.log debug;
    
  4. 儲存配置並退出配置檔案。

將除錯日誌寫入記憶體

除錯日誌可以使用迴圈緩衝區寫入記憶體。優點是,在高負載下,除錯級別的日誌記錄對效能影響不大。

要啟用將除錯日誌寫入記憶體:

  1. 確保您的 NGINX 配置了 --with-debug 配置選項。執行命令並檢查輸出是否包含 --with-debug 行:

    nginx -V 2>&1 | grep -- '--with-debug'
    
  2. 在 NGINX 配置檔案中,使用在 main 上下文中指定的 error_log 指令啟用除錯日誌的記憶體緩衝區:

    error_log memory:32m debug;
    ...
    http {
        ...
    }
    

從記憶體中提取除錯日誌

可以使用在 GDB 偵錯程式中執行的指令碼從記憶體緩衝區中提取日誌。

要從記憶體中提取除錯日誌:

  1. 獲取 NGINX 工作程序的 PID:

    ps axu |grep nginx
    
  2. 啟動 GDB 偵錯程式:

    sudo gdb -p <在上一步中獲得的 nginx PID>
    
  3. 複製指令碼,將其貼上到 GDB 中並按“Enter”。該指令碼將在當前目錄中的 debug_log.txt 檔案中儲存日誌:

    set $log = ngx_cycle->log
    while $log->writer != ngx_log_memory_writer
        set $log = $log->next
    end
    set $buf = (ngx_log_memory_buf_t *) $log->wdata
    dump binary memory debug_log.txt $buf->start $buf->end
    
  4. 透過按下 CTRL+D 退出 GDB。

  5. 開啟位於當前目錄中的“debug_log.txt”檔案:

    sudo less debug_log.txt
    

選定 IP 的除錯日誌

可以為特定 IP 地址或 IP 地址範圍啟用除錯日誌。在生產環境中,記錄特定 IP 可能很有用,因為它不會對效能產生負面影響。IP 地址在事件塊中的 debug_connection 指令中指定;該指令可以定義多次:

error_log /path/to/log;
...
events {
    debug_connection 192.168.1.1;
    debug_connection 192.168.10.0/24;
}

每個虛擬主機的除錯日誌

通常,error_log 指令在主上下文中指定,因此適用於所有其他上下文,包括伺服器和位置。

但是,如果在特定伺服器或位置塊內指定了另一個 error_log 指令,則會覆蓋全域性設定,並且這樣的 error_log 指令將設定自己的日誌檔案路徑和除錯日誌級別。

要為特定虛擬主機設定除錯日誌,請在特定伺服器塊內新增 error_log 指令,並設定新的日誌檔案路徑和除錯日誌級別:

error_log /path1/to/log debug;
...
http {
    ...
    server {
    error_log /path2/to/log debug;
    ...
    }
}

要禁用特定虛擬主機的除錯日誌,請在特定伺服器塊內指定 error_log 指令,並僅指定日誌檔案路徑:

error_log /path/to/log debug;
...
http {
    ...
    server {
    error_log /path/to/log;
    ...
    }
}

啟用核心轉儲

核心轉儲檔案可以幫助識別和修復導致 NGINX 崩潰的問題。核心轉儲檔案可能包含諸如密碼和私鑰之類的敏感資訊,因此請確保對它們進行安全處理。

為了建立核心轉儲檔案,必須在作業系統和 NGINX 配置檔案中都啟用它們。

在作業系統中啟用核心轉儲

在作業系統中執行以下步驟:

  1. 指定一個工作目錄,用於儲存核心轉儲檔案,例如“/tmp/cores”:

    mkdir /tmp/cores
    
  2. 確保該目錄可由 NGINX 工作程序寫入:

    sudo chown root:root /tmp/cores
    sudo chmod 1777 /tmp/cores
    
  3. 禁用核心轉儲檔案的最大大小限制:

    ulimit -c unlimited
    

    如果操作以“Cannot modify limit: operation not permitted”結束,請執行以下命令:

    sudo sh -c "ulimit -c unlimited && exec su $LOGNAME"
    
  4. 為 setuid 和 setgid 程序啟用核心轉儲。

    • 對於 CentOS 7.0、Debian 8.2、Ubuntu 14.04,請執行以下命令:
    echo "/tmp/cores/core.%e.%p" | sudo tee /proc/sys/kernel/core_pattern
    sudo sysctl -w fs.suid_dumpable=2
    sysctl -p
    
    • 對於 FreeBSD,請執行以下命令:
    sudo sysctl kern.sugid_coredump=1
    sudo sysctl kern.corefile=/tmp/cores/%N.core.%P
    

在 NGINX 配置中啟用核心轉儲

要在 NGINX 配置檔案中啟用核心轉儲:

  1. 開啟 NGINX 配置檔案:

    sudo vi /usr/local/etc/nginx/nginx.conf
    
  2. 使用 working_directory 指令定義一個目錄,該目錄將儲存核心轉儲檔案。該指令在主配置級別上指定:

    working_directory /tmp/cores/;
    
  3. 確保該目錄存在,並由 NGINX 工作程序寫入。在終端中執行以下命令:

    sudo chown root:root /tmp/cores
    sudo chmod 1777 /tmp/cores
    
  4. 使用 worker_rlimit_core 指令指定核心轉儲檔案的最大可能大小。該指令也在主配置級別上指定。如果核心轉儲檔案大小超過該值,將不會建立核心轉儲檔案。

    worker_rlimit_core 500M;
    

    示例:

    worker_processes   auto;
    error_log          /var/log/nginx/error.log debug;
    working_directory  /tmp/cores/;
    worker_rlimit_core 500M;
    
    events {
        ...
    }
    
    http {
        ...
    }
    

透過這些設定,核心轉儲檔案將在“/tmp/cores/”目錄中建立,只有當其大小不超過 500 兆位元組時才會建立。

從核心轉儲檔案中獲取回溯資訊

回溯提供了關於程式崩潰時出錯的資訊。

要從核心轉儲檔案中獲取回溯資訊:

  1. 使用 GDB 偵錯程式開啟核心轉儲檔案,命令格式為:

    sudo gdb <nginx_executable_path> <coredump_file_path>
    
  2. 輸入“backtrace”命令以從崩潰時的堆疊中獲取堆疊跟蹤資訊:

    (gdb) backtrace
    

如果“backtrace”命令返回“沒有可用的符號表資訊”訊息,則需要重新編譯 NGINX 二進位制檔案以包含除錯符號。請參閱NGINX和除錯符號。

從執行中的程序中轉儲NGINX配置

您可以從主程序記憶體中提取當前的NGINX配置。當您需要:

  • 驗證已載入的配置
  • 如果磁碟上的版本被意外刪除或覆蓋,恢復以前的配置

配置轉儲可以透過提供一個GDB指令碼來獲得,只要您的NGINX具有除錯支援。

確保您的NGINX已經構建了除錯支援(在configure引數列表中使用--with-debug選項)。執行命令並檢查輸出是否包含--with-debug行:

nginx -V 2>&1 | grep -- '--with-debug'

獲取NGINX工作程序的PID:

ps axu | grep nginx

啟動GDB偵錯程式:

sudo gdb -p <在上一步中獲取的NGINX PID>

複製並貼上指令碼到GDB中,然後按“Enter”鍵。該指令碼將配置儲存在當前目錄中的nginx_conf.txt檔案中:

set $cd = ngx_cycle->config_dump
set $nelts = $cd.nelts
set $elts = (ngx_conf_dump_t*)($cd.elts)
while ($nelts-- > 0)
set $name = $elts[$nelts]->name.data
printf "Dumping %s to nginx_conf.txt\n", $name
append memory nginx_conf.txt \
      $elts[$nelts]->buffer.start $elts[$nelts]->buffer.end
end

按下CTRL+D退出GDB。

開啟位於當前目錄中的nginx_conf.txt檔案:

sudo vi nginx_conf.txt

在請求幫助時
在請求除錯幫助時,請提供以下資訊:

  • NGINX版本、編譯器版本和配置引數。執行命令:
nginx -V
  • 當前完整的NGINX配置。請參閱從執行程序中轉儲NGINX配置

  • 除錯日誌。請參閱在NGINX配置中啟用除錯日誌

  • 獲取的回溯。請參閱啟用核心轉儲,獲取回溯資訊。

參考資料

https://docs.nginx.com/nginx/admin-guide/monitoring/debugging/

相關文章