php-fpm,以及现在比较火的workman,swoole,其都是使用的多进程的管理模式,使用manger进程,管理其子进程,今天通过纯php做了一个类似的小东西,这样以后再做守护脚本的时候,可以使用这种方式,好处就是,多进程,更能利用多核的优势,并且可以做平滑重启。
本代码实现的功能,可以自定义子进程数,比如你定3个子进程,运行会产生1个manger进程,3个work进程,通过linux信号,来实现,进程的平滑重启。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
<?php /** * Class PcntlProccess * 多进程守护任务管理 * * kill -s SIGUSR1 mange进程: 平滑重启所有子进程 * kill | kill -s SIGTERM mange进程:平滑stop所有进程 * kill | kill -s SIGUSR1 | kill -s SIGTERM 子进程,重启该子进程 * author chao * */ class PcntlProccess{ const proccess_num = 3;//子进程数 const proccess_name = 'php-proccess';//进程名前缀 protected $_pid; //入口进程 public function run(){ if(self::proccess_num > 0){ //启动进程 for ($i=0; $i<self::proccess_num; $i++) { $this->parentProccess(); } //SIGUSR1 留给用户使用,此处做reload平滑重启使用 pcntl_signal(SIGUSR1, function($this){ $this->sig_handler(SIGUSR1); }); // 程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和 处理. 通常用来要求程序自己正常退出. shell命令kill缺省产生这 个信号. pcntl_signal(SIGTERM, function($this){ $this->sig_handler(SIGTERM); }); //终止进程 终端线路挂断 pcntl_signal(SIGHUP, function($this){ $this->sig_handler(SIGHUP); }); cli_set_process_title(self::proccess_name . '-manger'); while (true) { // do something $pid = pcntl_waitpid(-1, $status, WUNTRACED | WNOHANG); if($pid>0){ $this->parentProccess($pid); } pcntl_signal_dispatch(); // 接收到信号时,调用注册的signalHandler() usleep(100000); } }else{ exit('proccess_num must > 0'); } } function sig_handler($signo){ switch ($signo) { case SIGUSR1: foreach($this->_pid as $key){ posix_kill($key,SIGUSR1); } echo date('Y-m-d H:i:s')." [manage] [SIGUSR1] all work reload\n"; break; case SIGTERM: foreach($this->_pid as $key){ posix_kill($key,SIGUSR1); } echo date('Y-m-d H:i:s')." [manage] [SIGTERM] stop\n"; die(); break; case SIGHUP: echo date('Y-m-d H:i:s')." [manage] [SIGHUP] linux clinet exit\n"; break; } } function sig_san_handler($signo){ switch ($signo) { case SIGUSR1: echo date('Y-m-d H:i:s')." [work] [SIGUSR1] work die\n"; die(); break; case SIGTERM: echo date('Y-m-d H:i:s')." [work] [SIGTERM] work die\n"; die(); break; case SIGHUP: echo date('Y-m-d H:i:s')." [work] [SIGHUP] linux clinet exit\n"; break; } } //父进程 public function parentProccess($id=''){ if(!empty($id)){ unset($this->_pid[$id]); } $pid = pcntl_fork(); if($pid == -1) { return false; } else { if($pid) { #父进程获得子进程的pid,存入数组 $this->_pid[$pid] = $pid; return true; } else { //开始发送,子进程执行完自己的任务后,退出。 $this->sanProccess(); exit; } } } public function sanProccess(){ cli_set_process_title(self::proccess_name . '-work'); echo date('Y-m-d H:i:s')." work proccess start\n"; pcntl_signal(SIGUSR1, function($this){ $this->sig_san_handler(SIGUSR1); }); pcntl_signal(SIGHUP, function($this){ $this->sig_san_handler(SIGHUP); }); pcntl_signal(SIGTERM, function($this){ $this->sig_san_handler(SIGTERM); }); while(1){ //todu pcntl_signal_dispatch(); sleep(1); } } } $obj = new PcntlProccess(); $obj->run(); |
php index.php命令行运行,会产生3个子进程,
1 2 3 4 5 6 |
[root@iZ28y2wmd7jZ ~]# ps -ef|grep php-proccess root 11536 11051 0 18:38 pts/0 00:00:00 grep --color=auto php-proccess root 13756 32171 0 Nov10 ? 00:00:06 php-proccess-work root 13757 32171 0 Nov10 ? 00:00:06 php-proccess-work root 13758 32171 0 Nov10 ? 00:00:06 php-proccess-work root 32171 1 0 Nov09 ? 00:02:37 php-proccess-manger |
你随意kill一个,管理进城会立即补充一个,传递SIGUSR1给子进程,会平滑重启比子进程,给主进城,就会平滑重启所有子进程,kill主进城,或者传递SIGHUP信号,会平滑的kill所有子进程,结束主进城。这样的好处就是主进城只负责监控子进程和自己的状态,运行更稳定,然后后期可以做一些子进程任务处理上限的控制,就可以试进城更稳定高效,信号试用kill -s 传递
升级版:
留作记录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |