热重启的基本业务逻辑是,将变动性大的业务逻辑加载过程放在OnWorkerStart方法中。
涉及到进程模型:
OnWorkerStart之后加载的代码都在各自进程中,OnWorkerStart之前加载的代码属于共享内存。
OnWorkerStart会由Worker或TaskWorker进程触发,区分是Worker进程还是Task进程的方法是:
if($worker_id >= $serv->setting['worker_num'])
{
//这个是Task进程
require_once __DIR__ . '/App/Handler/HeartBeatHandler.php';
$hand = new HeartBeatHandler();
$this->AddEventHandler($hand);
} else {
//这个是Worker进程
}
由此产生的问题的问题是,各个Worker或者Task进程New出来的对象是不共享的。
而OnTask事件是在Task进程中触发的,OnReceive等事件是在Worker进程中触发的。
在上例中,在所有的Task进程中的$this对象都添加了新的Handler,这些Handler在OnReceive事件中是访问不到的,因为OnReceive事件是在Worker进程中触发的。
相对的,如果想在OnReceive中访问这些Handler,则应该在Worker进程中添加。
如果通过worker_id细分到各个进程,则各个进程内部创建的对象都是不共享的。
如果希望全局共享,则应该在OnStart或者之前添加。
当然,这里既然涉及到了热重启,则需要通过kill -10命令Master进程执行Server_Reload方法,此方法会在Worker进程完成当前任务后重启,并触发OnWorkerStop事件。
在上例中,应在OnWorkerStop事件中清除已有的Handler,释放内存空间。然后会再度触发OnWorkerStart事件,实现Handler的代码热更新。
function OnWorkerStop(\swoole_server $server, $worker_id)
{
if ($worker_id >= $server->setting['worker_num'])//worker的进程,其他的是Task_Worker的进程
{
DILog("Worker Stop {$worker_id}"."/Count".count($this->handlerArray));
$this->handlerArray = [];
}
}
参考手册:
http://wiki.swoole.com/wiki/page/46.html
可以将公用的,不易变的php文件放置到onWorkerStart之前。这样虽然不能重载入代码,但所有worker是共享的,不需要额外的内存来保存这些数据。onWorkerStart之后的代码每个worker都需要在内存中保存一份
PS:为了更灵活,应将加载Handler的代码改成通过反射被动加载的方式。