Table of Contents
配置热加载:
case SIGUSR2:
nginx 有两种情况:
难点在于:
因为不能由各个子进程分别做监听, 只能父进程监听后, 确定监听sokcet列表, 然后fork出子进程, 由子进程继承监听socket.
启动后:
+-------------------------------+ | 0 | +-------------------------------+ | | +---+ +---+ | | | | | 1 | | 2 | | | | | +---+ +---+
向父进程0发信号, 派生出新的子进程:
+-------------------------------+ | 0 | +-------------------------------+ | | a| | +---+ +---+ +---+ +---+ | | | | | | | | | 1 | | 2 | | 3 | | 4 | | | | | | | | | +---+ +---+ +---+ +---+
父进程收到信号后, 解析新的配置, 得到新的需要监听的列表, 以及每个监听socket对应的配置, 并派生新worker, 新worker启动后, 向老worker 发送优雅关闭的信号即可, 最后达到这样:
+-------------------------------+ | 0 | +-------------------------------+ a| | +---+ +---+ | | | | | 3 | | 4 | | | | | +---+ +---+
考虑父进程收到信号后, 派生新worker的过程. 假设
那么父进程解析完新的配置文件后, 会对比监听列表, 决定关闭8002, 新开8003, 保留8000, 8001, 然后把这三个fd开着, fork出新worker.
新worker 直接使用新的配置结构即可.
这里父进程可以直接修改自己的老配置为新配置(不会影响到 老的worker自己的那一份老配置)
对于twemporxy这样单进程模型, 就不能这样做, 如果在运行时修改自己的配置, 一个请求很可能跨两种不同的配置. 这就容易出问题.
+-------------------------------+ | 0 | +-------------------------------+ | | +---+ +---+ | | | | | 1 | | 2 | | | | | +---+ +---+
发信号:
+-------------------------------+ | 0 | +-------------------------------+ | | | +---+ +---+ +----------------------+ | | | | | 3 | | 1 | | 2 | +----------------------+ | | | | | | +---+ +---+ +---+ +---+ | | | | | 4 | | 5 | | | | | +---+ +---+
发信号后0派生出一个新的master 3, 这个过程会把所有老的fd传给3, 由3来决定把哪些fd关掉. 新开哪些fd, 之后3会派生自己的worker.
0和3之间传递fd是通过环境变量来做的, 0会向环境变量里面写:
fds=3:8:72
这样的, 表示这三个listen fd, 子进程拿到这三个fd, 解析自己的配置, 看需要监听哪些端口, 和这些fd对比(这些fd可以通过getsockaddr获取所监听的端口)
传递fd: