好好学习,天天向上

uwsgi代码小札|gracefully reload之从停止说起

说明:以master为例

根据uwsgi文档,当uwsgi接收到SIGHUP信号的时候,会优雅地重载所有的worker和master进程。(参考:uwsgi中文

而在master_loop()方法(位于core/master.c)中,注册了接收到SIGHUP信号的处理方法为grace_them_alluwsgi_unix_signal(SIGHUP, grace_them_all);

起始:void grace_them_all(int signum)

位于uwsgi/core/uwsgi.c中

在这个方法中,uwsgi会针对不同的模式,修改状态,关闭清理不同的进程。具体执行如下: 1. 检查uwsgi实例是否已经在重载,或者正在关闭。是则直接返回,以避免再次重载。 2. lazy模式下,对所有正在运行中的worker,调用uwsgi_curse(i, SIGHUP),然后直接返回 3. 设置uwsgi的状态为正在优雅重载(uwsgi.status.gracefully_reloading = 1;) 4. 调用uwsgi_destroy_processes() 1. 给spooler发送SIGKILL信号杀死spooler 2. 停止uwsgi的守护进程(daemon)们 3. 杀死gateway(来自uwsgi.h中的注释:gateway是由master管理的进程,用以扩展服务器的核心特性,它可以prefork或者spawn线程) 4. 杀死emperor 5. 如果定义了UWSGI_SSL,还要调用uwsgi_legion_announce_death()宣告legion的death状态 6. 如果设置了即使在重载时也要强制取消订阅请求(unsubscribe_on_graceful_reload),那么则取消订阅(调用uwsgi_unsubscribe_all()) 7. 对于每个worker,如果不是master的话,则调用uwsgi_curse(i, SIGHUP);来杀死worker 8. 对于每个mule,如果不是父mule的话,则调用uwsgi_curse_mule(i, SIGHUP);来杀死Mule

整个过程图如下: grace_them_all(int signum)

给指定worker id的worker发送死亡信号sig:uwsgi_curse

位于uwsgi/core/master_utils.c中

1
2
3
4
5
6
7
8
9
void uwsgi_curse(int wid, int sig) {
// 设置worker的最后死亡期限
uwsgi.workers[wid].cursed_at = uwsgi_now();
uwsgi.workers[wid].no_mercy_at = uwsgi.workers[wid].cursed_at + uwsgi.worker_reload_mercy;
// 给worker发送信号sig
if (sig) {
(void) kill(uwsgi.workers[wid].pid, sig);
}
}

管理worker的优雅重载:void gracefully_kill(int signum)

位于uwsgi/core/uwsgi.c中

master通过kill()函数来向worker发送SIGHUP信号。 而在uwsgi_worker_run()方法中注册了信号SIGHUP的处理方法为gracefully_killuwsgi_unix_signal(SIGHUP, gracefully_kill);。我们来看看这个方法又进行了什么操作: 1. 将worker管理的下一个请求(manage_next_request)置为0(表示的意思要再研究下) 2. 对于多线程,等待线程终止(wait_for_threads()),等待请求处理完成之后,在需要的时候(worker.close_sockets不为0)关闭所有的socket,最后调用exit(UWSGI_RELOAD_CODE)退出。结束该方法。 3. 对于异步模式,目前没有什么好的方式进行优雅重载,因此处理方式则是,在需要的时候(worker.close_sockets不为0)关闭所有的socket,然后调用exit(UWSGI_RELOAD_CODE)退出。结束该方法。 4. 对于无待处理请求的worker,在需要的时候(worker.close_sockets不为0)关闭所有的socket,然后调用exit(UWSGI_RELOAD_CODE)退出

这里的exit()函数并非系统的exit,而是一个宏定义:#define exit(x) uwsgi_exit(x)

图解如下: gracefully_kill(int signum)

退出:void uwsgi_exit(int status)

  1. 将uwsgi的last_exit_code属性值为status值
  2. 调用系统函数exit退出当前进程

通过上面一系列操作,uwsgi就完成了重载中的stop一步。接下来就是start了。这个阶段,我们稍后再说~~

参考

请言小午吃个甜筒~~