前言
Nginx的日志分割中,涉及到一条指令:
kill USR1 $(cat /usr/local/nginx/logs/nginx.pid)
通过其他一些博客资料显示,信号量为USR1 表示重新打开文件的意思
本着深入学习的念头,深入了解后,总结如下,如果不对,欢迎勘正;
*******************************华丽的分割线******************************************
上面的指令,包括几个知识点:
1.kill命令
2.信号量
3.cat 跟 $() :略
4.nginx.pid :略
********************************************************************************************
1.kill命令
--为Linux系统的命令,目的是为了终止指定的程序,通过man kill可以看到文档对kill的解释:
The command kill sends the specified signal to the specified process or process group. If no signal is specified, the TERM signal is sent. The TERM signal will kill processes which do not catch
this signal. For other processes, it may be necessary to use the KILL (9) signal, since this signal cannot be caught.
Most modern shells have a builtin kill function, with a usage rather similar to that of the command described here. The '-a' and '-p' options, and the possibility to specify processes by command
name are a local extension.
If sig is 0, then no signal is sent, but error checking is still performed.
第一句话的意思为:kill命令发送指定的信号给指定的进程或进程组(其他暂不理),也就是说,Kill可以通过发送信号量来终止进程;.
其格式如下
格式:kill [-s signal|-p] [-q sigval] [-a] [--] pid
选项 -s解释如下:
-s, --signal signal
Specify the signal to send. The signal may be given as a signal name or number.
(发送指定的信号量,该信号量可以是信号名或者数字.如: (9) 或 HUP)
2.信号量
信号量是为了协调不同进程之间针对某一共享资源或者其他操作的通信方式,由于篇幅原因,不多加解释,下面的链接是个人觉得讲得挺好的,Mark一下:
https://blog.csdn.net/stt2836/article/details/88814282
那么,通过知识点1可以推断出:USR1为信号量.通过了解后发现:USR1为用户自定义的信号量;即可以被需要的进程所定义.由于kill发送该信号量到nignx进程,所以应该在nginx代码中定义.
通过阅读nginx的代码看到定义的地方:
在文件:core/ngx_config.h中
#if (NGX_LINUXTHREADS)
#define NGX_REOPEN_SIGNAL INFO
#define NGX_CHANGEBIN_SIGNAL XCPU
#else
#define NGX_REOPEN_SIGNAL USR1
#define NGX_CHANGEBIN_SIGNAL USR2
#endif
根据NGX_LINUXTHREADS来定义变量代表信号量的意思;由变量NGX_REOPEN_SIGNAL的名字可以翻译为"重新打开的信号量",重新打开什么呢?
继续翻阅代码:
在./os/unix/ngx_process.c中
310 ngx_signal_handler(int signo)
//ngx_signal_handler函数为处理nginx信号量的函数,其中在case ngx_signal_value分支做出如下处理:
{
... ....
360 case ngx_signal_value(NGX_REOPEN_SIGNAL):
361 ngx_reopen = 1; //将该reopen状态打开,进程在看到这个变量是1的时候,就采取相应的操作;
362 action = ", reopening logs"; //定义动作类型为打开logs日志.为了方便后面写入日志;
363 break; //退出循环检测;
...
435 ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
436 "signal %d (%s) received%s", signo, sig->signame, action);.
... ...
}
当我们发送:kill -USR1 $(cat /usr/local/nginx/logs/nginx.pid)命令的时候,
通过查看error.log日志看到:
2019/06/23 18:10:00 [notice] 6512#0: signal 10 (SIGUSR1) received, reopening logs
2019/06/23 18:10:00 [notice] 6512#0: reopening logs
2019/06/23 18:10:00 [notice] 10490#0: reopening logs
- 注:如果想要看到该信息的话,需要在nginx.conf配置文件中,将errorlog的级别调为[notice],再重启服务,
- 注2:如果想要查看更多的debug信息.需要配置模块:./configure --with-debug(可以查看nginx支持的模块)
如下所示:
worker_processes 1;
error_log logs/error.log notice;
events {
worker_connections 1024;
}
其实到这里,就可以知道.USR1的信号量是为了告诉nginx进程重新打开日志文件;
但是考虑到,Kill不是终止进程么?那nginx怎么重新打开日志文件呢?,打开后nginx的进程会怎么样呢?继续跟进代码;
进程通过循环调用ngx_master_process_cycle(进程入口) 函数检测,该函数在nginx初始化时调用,并通过命令:
for ( ;; ) {...}重复调用;
263 if (ngx_reopen) { //如果ngx_reopen为真(1)
264 ngx_reopen = 0; ///将设置ngx_reopen为假;状态标识符.
265 ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");//写入error-log日志中,
266 ngx_reopen_files(cycle, ccf->user); //新建log文件;
267 ngx_signal_worker_processes(cycle,
268 ngx_signal_value(NGX_REOPEN_SIGNAL));
269 }
注:其中NGX_LOG_NOTICE表示日志的级别;cycle为结构体,记录重要的变量,cycle->log为文件标识符,Linux通过文件标识符对文件进行操作,这也是为什么做分割的时候,修改完名字后需要kill进程,否则就算改了名字.nginx根据标识符还是会往改了名字后的文件进行写入动作;
进程调用函数:ngx_reopen_files新建新的日志文件,并修改权限等操作:
1081 ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user)
1082 {
... ...
1110 fd = ngx_open_file(file[i].name.data, NGX_FILE_APPEND, //创建文件fd为文件描述流
1111 NGX_FILE_CREATE_OR_OPEN, NGX_FILE_DEFAULT_ACCESS);
....... //创建失败的操作.写入log
1123 #if !(NGX_WIN32) //判断平台;修改权限等操作
... ...
1143 if (fi.st_uid != user) { //修改所有者
1144 if (chown((const char *) file[i].name.data, user, -1) == -1) {
...
1157 }
1158
... ...
1163 if (chmod((const char *) file[i].name.data, fi.st_mode) == -1) { //修改权限
1164 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1165 "chmod() \"%s\" failed", file[i].name.data);
1174 }
1175 }
1176 }
1203 }
1204
其中ngx_open_file函数的功能是打开文件,如果文件不存在则创建新的文件;(不重要,习惯性跟进,可以不看)
#define ngx_open_file(name, mode, create, access) \
open((const char *) name, mode|create|O_BINARY, access)
#else
#define ngx_open_file(name, mode, create, access) \
open((const char *) name, mode|create, access)
#endif
ngx_reopen_files函数执行完毕后,调用了ngx_signal_worker_processes函数进行进程管理:干掉老进程,创建新的进程;
535 if (kill(ngx_processes[i].pid, signo) == -1) { //如果终止进程失败,写入日志
... ...
547 }
548
至此,总结如下:
- 1.kill命令中.9也是信号量,表示为强制终止进程.发送其他信号量可以与进程进行沟通(沟通怎么死.....)
- 2.USR1信号量被nginx定义,为重新打开日志;当kill命令发送USR1时,nginx会重新打开日志文件,并重新创建进程;
- (重新写遗书后再死............)
注:一直以为发送USR1后nginx进程不死,只是针对日志文件做操作....梳理清楚后就懂了.
转自
https://blog.csdn.net/xinfuxuan4/article/details/93386815