Nginx重载过程源码阅读
Contents
假定读者有一定的Linux系统调用的相关知识, 至少要简单了解fork
操作, 以及简单的进程间通信.
简单探讨一下master-slave的通信机制以及通信过程.
开始进入重载逻辑
平时我在服务器中重载Nginx大概有以下两种操作:
1 | nginx -s reload |
重载Nginx就是向Nginx的master进程发送SIGHUP
信号, 然后由master进行
新建worker以及删除旧worker的操作.
信号的发送与处理过程不是我这篇博客的重点, 如果你对这个过程有兴趣, 可以参考这里:
从nginx1.17.9源码理解nginx -s reload
我直接从检查重载的地方开始讲
1 | // src/os/unix/ngx_process_cycle.c |
创建新的worker进程
1 | static void |
Nginx启动进程的过程
启动进程的函数比较复杂, 我删除了一些在重载时不用的逻辑, 把自己能看懂的地方讲一下吧.
1 | // src/os/unix/ngx_process.c |
worker进程初始化与状态处理
1 | static void |
父子进程通信过程
Nginx中, 进程通信是基于socketpair
的形式, 由父子进程分别持有一个socket,
关于Nginx进程创建的部分, 我简单书写一下伪代码, 希望能帮助大家理解
1 | 要生成第i个进程 |
删除旧worker
1 | static void |
总结
参考资料
nginx master-worker进程工作原理 nginx源码分析1———进程间的通信机制一(信号量)
附录
socketpair初始化之后, 一些代码优化的思考
原始的代码是这样的
1 | // src/os/unix/ngx_process.c |
可以看到, 多次使用了return语句, 并且ngx_close_channel也被多次使用了, 先前有了解过Linux内核代码, 上面的代码其实可以用goto语句进行简化的, 下面是我进行简化的一个版本:
1 | // C语言语法比较注重细节, 我简单用伪代码带过吧, 有机会可以提一个PR |
这里增加了goto语句其实简化了许多逻辑, 而且不用担心出错后忘记close_channel的问题, 感觉这里是使用goto语句合适的位置.
如何在Nginx中打印自己的日志
想不通为什么自己调用ngx_log_error
时打印不出来日志, 索性直接用fprintf(stderr, "hello world");
这种形式了, 反正也只是调试而已.
https://stackoverflow.com/questions/20187630/nginx-logging-in-module