一:信號監聽
信號:由用戶、系統或者進程發給目標進程的信息,以通知目標進程某個狀態的改變或系統異常
信號查看: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\r\n"; $http_resonse .= "Content-Type: text/html;charset=UTF-8\r\n"; $http_resonse .= "Connection: keep-alive\r\n"; $http_resonse .= "Server: php socket server\r\n"; $http_resonse .= "Content-length: " . strlen($content) . "\r\n\r\n"; $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); } }); }