一:信号监听
信号:由用户、系统或者进程发给目标进程的信息,以通知目标进程某个状态的改变或系统异常
信号查看:kill -l
SIGHUP 终止进程 终端线路挂断 SIGINT 终止进程 中断进程 SIGKILL 终止进程 杀死进程 SIGPIPE 终止进程 向一个没有读进程的管道写数据 SIGALARM 终止进程 计时器到时 SIGTERM 终止进程 软件终止信号 SIGSTOP 停止进程 非终端来的停止信号 SIGTSTP 停止进程 终端来的停止信号 SIGCONT 忽略信号 继续执行一个停止的进程 SIGURG 忽略信号 I/O紧急信号 SIGIO 忽略信号 描述符上可以进行I/O SIGPROF 终止进程 统计分布图用计时器到时 SIGUSR1 终止进程 用户定义信号1 SIGUSR2 终止进程 用户定义信号2 SIGVTALRM 终止进程 虚拟计时器到时
swoole热重启命令:
1、kill -SIGTERM|-15 master_pid 终止Swoole程序,一种优雅的终止信号,会待进程执行完当前程序之后中断,而不是直接干掉进程 2、kill -USR1|-10 master_pid 重启所有的Worker进程 3、kill -USR2|-12 master_pid 重启所有的Task Worker进程
重启子进程、拉起子进程代码:
<?php class Worker { //监听socket protected $socket = NULL; //连接事件回调 public $onConnect = NULL; //接收消息事件回调 public $onMessage = NULL; public $workerNum = 4; public $addr; public $worker_pid; public $master_pid; public function __construct($socket_address) { $this->addr=$socket_address; $this->master_pid = posix_getpid(); } //创建子进程 public function fork($worker_num) { for ($i = 0; $i < $worker_num; $i++) { $pid = pcntl_fork(); if ($pid < 0) { exit('创建失败'); } else if ($pid > 0) { //存储子进程id $this->worker_pid[]=$pid; } else { $this->accept(); exit(); } } } public function accept() { $opts = array( 'socket' => array( 'backlog' => '10240', ), ); $context = stream_context_create($opts); stream_context_set_option($context,'socket','so_reuseport',1); $this->socket = stream_socket_server($this->addr,$error,$errstr, STREAM_SERVER_BIND|STREAM_SERVER_LISTEN,$context); swoole_event_add($this->socket, function ($fd) { //服务端接收客户端请求 $clientSocket = stream_socket_accept($this->socket); if (!empty($clientSocket) && is_callable($this->onConnect)) { call_user_func($this->onConnect, $clientSocket); } swoole_event_add($clientSocket, function ($fd) { $buffer = fread($fd, 65535); //如果数据为空,或者为false,不是资源类型 if (empty($buffer)) { if (feof($fd) || !is_resource($fd)) { //触发关闭事件 fclose($fd); } } if (!empty($buffer) && is_callable($this->onMessage)) { call_user_func($this->onMessage, $fd, $buffer); } }); }); } /** * 捕获信号 * 监视worker进程.拉起进程 */ public function monitorWorkers(){ //注册信号事件回调,是不会自动执行的 pcntl_signal(SIGUSR1, array($this, 'signalHandler'),false); //重启woker进程信号 // pcntl_signal(SIGUSR1,array($this,'signalHandler'),false); //重启worker进程信号 $status = 0; //回收子进程 while(1){ //reload // 当发现信号队列,一旦发现有信号就会触发进程绑定事件回调 pcntl_signal_dispatch(); $pid = pcntl_wait($status); //当信号到达之后就会被中断 //ctrl+c //如果进程不是正常情况下的退出,重启子进程,我想要维持子进程个数 if($pid>1 && $pid != $this->master_pid && !pcntl_wifexited($status)){ $index=array_search($pid,$this->worker_pid); $this->fork(1); var_dump('拉起子进程'); unset($this->worker_pid[$index]); } pcntl_signal_dispatch(); //进程重启的过程当中会有新的信号过来,如果没有调用pcntl_signal_dispatch,信号不会被处理 } } public function signalHandler($sigo){ switch ($sigo){ case SIGUSR1: $this->reload(); echo '收到重启信号'; break; } } public function reload(){ foreach($this->worker_pid as $index =>$pid){ posix_kill($pid,SIGKILL); var_dump("杀掉的子进程$pid"); unset($this->worker_pid[$index]); $this->fork(1); } } public function start() { $this->fork($this->workerNum); $this->monitorWorkers(); //监视程序,捕获信号,监视worker进程 } } $worker = new Worker('tcp://0.0.0.0:9801'); $worker->onConnect = function ($args) { echo "新的连接来了.{$args}.PHP_EOL"; }; $worker->onMessage = function ($conn, $message) { // var_dump($conn, $message); $content = "hello word qwe"; $http_resonse = "HTTP/1.1 200 OK "; $http_resonse .= "Content-Type: text/html;charset=UTF-8 "; $http_resonse .= "Connection: keep-alive "; $http_resonse .= "Server: php socket server "; $http_resonse .= "Content-length: " . strlen($content) . " "; $http_resonse .= $content; fwrite($conn, $http_resonse); }; $worker->start();
cli运行:
二:inotify热重启
inotify:是linux内核提供的一组系统调用,她可以监控文件系统操作,比如文件或者目录的创建、读取、写入、权限修改、删除等
public function start() { //获取配置文件 $this->watch(); $this->fork($this->workerNum); $this->monitorWorkers(); //监视程序,捕获信号,监视worker进程 } /** * 文件监视,自动重启 */ protected function watch(){ $init=inotify_init(); //初始化 $files=get_included_files(); foreach ($files as $file){ inotify_add_watch($init,$file,IN_MODIFY); //监视相关的文件 } //监听 swoole_event_add($init,function ($fd){ $events=inotify_read($fd); if(!empty($events)){ posix_kill($this->master_pid,SIGUSR1); } }); }