引言
当程序出现问题时,调试有助于定位程序代码中的缺陷。它通常用于开发或测试第三方模块、实验性模块。
NGINX的调试功能包括调试日志,以及生成核心转储文件并进一步取得回溯信息。
配置用于调试的NGINX二进制程序
首先,需要在NGINX二进制程序中启用调试支持。NGINX Plus已经提供nginx-debug程序;开源NGINX则需要重新编译。
配置F5 NGINX Plus二进制程序
从Release 8开始,NGINX Plus在标准二进制程序之外同时提供nginx-debug。要启用调试,需要从nginx切换到nginx-debug。打开终端并运行:
service nginx stop && service nginx-debug start
完成后,在配置文件中启用调试日志。
编译开源NGINX二进制程序
要在开源NGINX中启用调试,需要在configure脚本中指定--with-debug标志并重新编译。
编译带有调试支持的开源NGINX:
-
下载并解压NGINX源码,进入源码目录。参见下载源码。
-
获取NGINX的配置参数列表,运行:
nginx -V 2>&1 | grep arguments -
将
--with-debug添加到配置参数列表,运行configure脚本:./configure --with-debug <other configure arguments> -
编译并安装NGINX:
shell sudo make sudo make install -
重启NGINX。
NGINX与调试符号
调试符号可以提供额外的调试信息,包括函数、变量、数据结构、源文件和行号。
NGINX默认使用包含调试符号的-g标志编译。
但如果执行回溯时出现No symbol table info available错误,说明调试符号缺失,需要重新编译NGINX并加入调试符号支持。
具体编译器标志取决于所用编译器。例如,对GCC编译器:
-
使用
-g标志包含调试符号。 -
通过
-O0禁用编译优化,使调试器输出更易理解:./configure --with-debug --with-cc-opt='-O0 -g' ...
在NGINX配置中启用调试日志
调试日志记录错误及调试相关信息,默认禁用。要启用它,先确保NGINX编译时支持调试,参见配置用于调试的NGINX二进制程序,再在配置文件中为error_log指令指定debug参数。调试日志可以写入文件、已分配的内存缓冲区、标准错误输出或syslog。
建议在配置的main层级启用调试日志,以获得完整情况。
将调试日志写入文件
在高负载下,写入文件可能降低性能。文件也可能快速增长并耗尽磁盘空间。为减少负面影响,可以改为写入内存缓冲区,或只记录指定IP地址。详见将调试日志写入内存和指定IP的调试日志。
启用文件调试日志:
-
确保NGINX配置时使用了
--with-debug选项。运行以下命令,检查输出是否包含它:nginx -V 2>&1 | grep -- '--with-debug' -
打开NGINX配置文件:
sudo vi /etc/nginx/nginx.conf -
找到默认位于
main上下文中的error_log指令,将日志级别改为debug。必要时更改日志文件路径:error_log /var/log/nginx/error.log debug; -
保存配置并退出编辑器。
将调试日志写入内存
调试日志可以写入使用循环缓冲区的内存。其优势是:高负载下,debug级别日志不会显著影响性能。
启用内存调试日志:
-
确保NGINX配置时使用了
--with-debug选项。运行以下命令并检查输出:nginx -V 2>&1 | grep -- '--with-debug' -
在NGINX配置文件的
main上下文中,使用error_log指定用于调试日志的内存缓冲区:nginx error_log memory:32m debug; ... http { ... }
从内存中提取调试日志
可以在GDB调试器中执行脚本,从内存缓冲区提取日志。
提取内存中的调试日志:
-
取得NGINX工作进程的PID:
ps axu |grep nginx -
启动GDB调试器:
sudo gdb -p <nginx PID obtained at the previous step> -
复制以下脚本,粘贴到GDB并按回车。它会将日志保存到当前目录中的
debug_log.txt:nginx 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 -
按
CTRL+D退出GDB。 -
打开当前目录中的
debug_log.txt:sudo less debug_log.txt
指定IP的调试日志
可以仅为某个IP地址或一个IP范围启用调试日志。这种方式适合生产环境,可避免不必要的性能影响。IP地址通过events块中的debug_connection指令指定;该指令可以定义多次:
error_log /path/to/log;
...
events {
debug_connection 192.168.1.1;
debug_connection 192.168.10.0/24;
}
各虚拟主机的调试日志
通常,error_log指令在main上下文中指定,因此会应用到server和location等其他上下文。但若某个server或location块又定义了error_log,就会覆盖全局设置,并使用自己的日志路径和级别。
要为指定虚拟主机设置调试日志,在相应server块中添加error_log,指定新的日志路径及debug级别:
error_log /path1/to/log debug;
...
http {
...
server {
error_log /path2/to/log debug;
...
}
}
要关闭某个虚拟主机的调试日志,在其server块中定义error_log,仅指定日志文件路径:
error_log /path/to/log debug;
...
http {
...
server {
error_log /path/to/log;
...
}
}
启用核心转储
核心转储文件有助于定位和修复导致NGINX崩溃的问题。它可能包含密码、私钥等敏感信息,必须安全处理。
要生成核心转储文件,必须同时在操作系统与NGINX配置中启用。
在操作系统中启用核心转储
在操作系统中执行:
-
指定保存核心转储的工作目录,例如
/tmp/cores:mkdir /tmp/cores -
确保NGINX工作进程能够写入该目录:
shell sudo chown root:root /tmp/cores sudo chmod 1777 /tmp/cores -
取消核心转储文件的最大大小限制:
sudo prlimit --core=unlimited:unlimited --pid $(cat /run/nginx.pid)如果操作返回
Cannot modify limit: operation not permitted,运行以下命令:sudo sh -c "ulimit -c unlimited && exec su $LOGNAME" -
为setuid和setgid进程启用核心转储。
对CentOS 7.0、Debian 8.2和Ubuntu 14.04,运行:
shell echo "/tmp/cores/core.%e.%p" | sudo tee /proc/sys/kernel/core_pattern sudo sysctl -w fs.suid_dumpable=2 sysctl -p对FreeBSD,运行:
shell sudo sysctl kern.sugid_coredump=1 sudo sysctl kern.corefile=/tmp/cores/%N.core.%P
在NGINX配置中启用核心转储
在NGINX配置文件中启用核心转储:
-
打开配置文件:
sudo vi /usr/local/etc/nginx/nginx.conf -
使用working_directory指令指定保存核心转储的目录。该指令位于
main配置层级:working_directory /tmp/cores/; -
确保目录存在,并允许NGINX工作进程写入。打开终端运行:
shell sudo chown root:root /tmp/cores sudo chmod 1777 /tmp/cores -
使用worker_rlimit_core指定核心转储文件的最大允许大小,该指令同样位于
main层级。如果转储文件超过这个大小,就不会生成。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 {
...
}
使用这些设置,仅当核心转储文件不超过500MB时,才会在/tmp/cores/目录中生成。
从核心转储文件取得回溯
回溯从核心转储文件中提供程序崩溃时的异常情况。
取得回溯:
-
使用以下模式,在GDB中打开核心转储文件:
sudo gdb <nginx_executable_path> <coredump_file_path> -
输入
backtrace,取得崩溃时的调用栈:(gdb) backtrace
如果backtrace返回No symbol table info available,需要重新编译NGINX二进制程序并加入调试符号。参见NGINX与调试符号。
从运行中的进程导出NGINX配置
可以从内存中的主进程提取当前NGINX配置。这在以下情况很有帮助:
- 核实实际加载的是哪个配置。
- 磁盘上的配置被意外移除或覆盖后,恢复此前的配置。
只要NGINX具有调试支持,就可以通过GDB脚本导出配置。
-
确保NGINX构建时启用了调试支持,即配置参数列表中包含
--with-debug。运行命令检查:nginx -V 2>&1 | grep -- '--with-debug' -
取得NGINX工作进程的PID:
ps axu | grep nginx -
启动GDB调试器:
sudo gdb -p <nginx PID obtained at the previous step> -
复制以下脚本并粘贴到GDB,按回车。脚本将配置保存到当前目录的
nginx_conf.txt:nginx 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配置中启用调试日志。
原文:调试NGINX;作者:F5 NGINX文档贡献者。版本或日期:以抓取时的官方版本为准。原文及源码权利归相应权利人所有。











暂无评论内容