十五、Swoole 基础学习笔记 - Swoole 守护进程&信号&平滑重启
hi,我是温新,一名PHPer
文章基于 Swoole 5.0.1 版本编写。
学习目标:守护进程启动服务后的相关操作,如重启等
说明:本篇文章结合官方文档编写及参考网络资料编写,虽非全部原创,但也是结合了自己的理解,若转载请附带本文 URL,编写不易,持续编写更不易,谢谢!
守护进程
守护进程(daemon)是一种长期生存的进程,它不受终端控制,可以在后台运行。如 ngxin、php-fpm等一般都是作为守护进程在后台提供服务。
守护进程可以在后台运行,但也存在缺点。启用守护进程后,server 内所有的标准输出都会被丢弃,这也就是说,进程运行过程中出现的异常也将无法追踪。为此可以配置 log_file,配置后 swoole 在运行时,会把所有的标准输出记录到该文件。
配置守护进程
$server->set([
// 启用守护进程
'daemonize' => true,
'log_file' => __DIR__ . '/server.log'
]);
平滑重启
Server 启动后,由于程序常驻内存,因此,当代码有修改时,需要使用 Ctrl + c
或 kill
来终端程序允许,然后再重新启动使之修改的代码生效。
若是处于生产环境,当有新功能增加时,需要中断服务然后重新启动,想想这后果是非常严重的。
在 Swoole 中可以使用平滑重启,而平滑重启是对 Server 发送特定的信号。那么什么是信号?
什么是信号?
信号以 SIG 开头,如常用的 Ctrl + c 其实就是向服务发送 SIGINT 的信号,也就是终端服务。在 Swoole 中,可以向主进程发送各种不同的信号,主进程会根据收到的信号类型做出不同的处理。常用信号如下:
- 1、SIGTERM,一种优雅的终止信号,进程执行完当前程序后再中断。使用:
kill -SIGTERM master_pid
; - 2、SIGUSR1,重启所有 Worker 进程。使用:
kill -USR1 master_pid
; - 3、SIGUSR2,重启所有 Task 进程。使用:
kill -USR2 master_pid
。
当 USR1 信号被发送给 Master 进程后,Master 进程会将同样的信号通过 Manager 进程转发给 Worker 进程,收到该信号的 Worker 进程会在处理完正在执行的逻辑后,释放进程内存,关闭自己,然后由 Manager 进程重启一个新的 Worker 进程。新的 Worker 进程会占用新的内存空间。
平滑重启的原理:当主进程收到 USR1 信号时,主进程会向一个子进程发送安全退出的信号。安全退出指的是等到子进程处理完手头的工作后再将其杀死,可以理解为过河拆桥。
到这里可以知道,平滑重启本质是让旧的子进程逐一退出然后再创建新的进程。为了在平滑重启时不影响用户,需要保持业务进程是无状态的。
注意:
1、在 Swoole 中,重启只能针对 Worker 进程,写在 master 进程和 manager 进程中的更新代码不会生效,也就是,只有人 onWorkerStart 回调之后加载的文件,重启才能有意义。在 Worker 进程启动前就加载到内存中的文件,若要生效,就只能关闭 Server再重启;
2、直接写在 Worker 代码中的逻辑不会生效,即使是发送了信号。需要通过 include 方式引入相关代码才会生效。
案例演示
修改代码未生效
Test 类,用于处理服务端接收的数据
<?php
// 14-test.php
class Test
{
public function run($data)
{
echo $data . PHP_EOL;
}
}
服务端代码
<?php
// 14-swoole-server.php
// 引入其他文件
require_once '14-test.php';
$server = new Swoole\Server('0.0.0.0', 9501, SWOOLE_PROCESS);
$server->on('Receive', function ($server, $fd, $reactorId, $data) {
// 发送消息
$test = new Test;
$test->run($data);
});
$server->start();
客户端使用 telnet 进程连接。
向服务端发送消息,可以看到,服务端已经接收到了客户端发送的数据。
$php 14-swoole-server-1.php
hello
1)修改 test 类方法:
<?php
class Test
{
public function run($data)
{
echo 'hi:' . $data . PHP_EOL;
}
}
2)现在我们找到服务端进程号并平滑重启:
$netstat -nltp | grep 9501
tcp 0 0 0.0.0.0:9501 0.0.0.0:* LISTEN 19495/php
# 平滑重启
$kill -USR1 19495
3)再次连接服务端并向服务端发送数据,发现修改后的代码未生效。
未生效的原因是:新的代码只有在 onWorkerStart 之后加载进来才会生效。
修改代码,平滑重启使之生效
<?php
// 14-swoole-server-1.php
$server = new Swoole\Server('0.0.0.0', 9501, SWOOLE_PROCESS);
$server->set([
'worker_num' => 1,
'daemonize' => true,
'log_file' => __DIR__ . '/server.log',
]);
$server->on('Receive', function ($server, $fd, $reactorId, $data) {
$test = new Test;
$test->run($data);
});
$server->on('Workerstart', function($server, $workerId)
// workerStart 之后引入,平滑重启会生效
require_once '14-test.php';
});
$server->start();
这后修改后,就实现了热重启。
本篇文章到此结束,我是温新,下篇文章继续学习 Swoole。