== 信号处理 一般情况下,信号只需要往 Master 进程发送就可以了。然而,Unicorn 在内部也用信号的方式把信号发往各个子进程。除了 TTIN/TTOU 之外,信号的处理方式和 {nginx}[http://nginx.net/] 相似,所以可以共用 Unicorn 和 Nginx 的管理脚本。 这是一个 init script 管理分布式 Unicorn 的例子: http://unicorn.bogomips.org/examples/init.sh === Master 进程 * HUP - 重新载入配置文件,并且完整的重启所有子进程。 如果 "preload_app" 为 false (默认的),那么子进程将会在重启的时候载入所有的应用程序代码。 如果 "preload_app" 为 true,那么应用程序代码改变将不会被重新载入;USR2 + QUIT (看下面的内容) 就是用来解决这这样的场景。在重启的时候,+Gem.refresh+ 会被调用,所以你新装的 RubyGems 也会被载入。不建议你在 Unicorn 跑着的时候卸载你应用程序依赖的 RubyGems,不然重新开启的子进程将会由于卸载掉的 Gem 依赖而启动失败。 * INT/TERM - 快速关闭,立刻杀掉所有子进程。 * QUIT - 正常关闭,关闭前会等待子进程完成进行中请求。 * USR1 - Master 进程与子进程重新打开所有的 log 文件,详见 Unicorn::Util.reopen_logs 是如何处理 log 的。 * USR2 - 重新启动,将会启动一个新的 Master 进程,当启动完成并且验证通过或,会发送 QUIT 到原始进程上面。 * WINCH - 正常结束子进程,但保持 Master 进程活着。 此方法只适用于 Master 进程。 * TTIN - 增加一个子进程。 * TTOU - 减少一个子进程。 === 子进程 提示: Unicorn 4.8 里面大多数场景 Master 进程是通过 pipe 往子进程发送信号,而不是用 kill。然而也是支持信号的方式。 一般不需要直接往子进程发送信号,如果 Master 进程在运行,任何一个退出的子进程将会自动重新开启。 * INT/TERM - 快速关闭,立刻退出。 除非 WINCH 已经发给 Master 了(或 Master 已经没了),不然 Master 将会自动重新开启一个新进程出来。 直接关闭在 Unicorn 4.8 里面任然是用 kill(2) 的方式,而不是用内部 pipe。 * QUIT - 正常退出,直达当前处理结束。 同样的,如果 Master 还在,会又新开一个新的子进程出来。 * USR1 - 让此子进程重新打开 log 文件。 详见 Unicorn::Util.reopen_logs 是如何处理 log。 Log 文件在进程处理完当前请求之前不会重新打开的, 所以同一个请求的多行的 log 最终会写到同一个文件里面。 如果你的字进程启用了 user/group-switching,不建议用 "killall -USR1 unicorn" 直接对子进程发送 USR1 的信号。 你会遇到文件权限的问题,子进程将会被迫重启。 如果是对 Master 进程发送 USR1 信号,它会在在下发信号给子进程之前,首先会确保日志文件有正确的权限。 === 运行中的 Unicorn 进程热更新过程 你是可以在不丢失已经接上的客户端连接的情况下,用一个新的 Unicorn 实例来替代老的。 那么做是可以重新载入你的应用程序源代码、Unicorn 配置、Ruby 可执行文件、以及所有的类库。 但是下面这些无法改变(和系统限制有关): 1. Unciron 的执行脚本路径。如果你想更换成另外一个 Ruby 安装路径,你可以修改 `#!` 行(PS: Bash script 的第一行)来执行不同的 Ruby 版本。 Unicorn Reload 过程和 Nginx 类似: 1. 发送 USR2 信号到 master 进程 2. 检查你的进程管理器或 pid 文件,看是否新的 master 是否启动成。如果使用 pid 文件,那么老进程的 pid 文件将会增加 ".oldbin" 后缀。 同时将会有两组 master 进程在同时运行,它们的 workers 都能接受请求。进程树看起来会是这样: unicorn master (old) \_ unicorn worker[0] \_ unicorn worker[1] \_ unicorn worker[2] \_ unicorn worker[3] \_ unicorn master \_ unicorn worker[0] \_ unicorn worker[1] \_ unicorn worker[2] \_ unicorn worker[3] 3. 现在可以发送 WINCH 到 old master 进程,于是会切换为仅 new workers 能处理请求。如果你是以交互模式启动 Unicorn(非 daemon),你可以跳过此步。后面第 5 步会有点困难,不过你依然可以跳过,如果不是 daemon 模式。 4. 现在你检查功能,确保从 old workers 切到 new workers 后,所有事情都正确运行。 5. 如果一切看起来都是正常的,你可以发送 QUIT 信号到 old master 来结束 old master 的进程。 如果有不正常的情况,你可以发送 HUP 信号到 old master 来恢复到 old master,然后发送 QUIT 到 new master 来终止。以达到回滚目的。