• swoole(5)信号监听、热重启


    一:信号监听

    信号:由用户、系统或者进程发给目标进程的信息,以通知目标进程某个状态的改变或系统异常

    信号查看: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);
                }
            });
        }
  • 相关阅读:
    Python 重定向 响应头
    经典案例:如何优化Oracle使用DBlink的SQL语句
    django 文件上传
    mysite下的url 映射到news下的视图
    django 只允许POST或者GET
    云端的SRE发展与实践
    django 捕获url
    django 在自己app下编写自定义sql
    对偶学习及其在机器翻译中的应用
    对偶学习及其在机器翻译中的应用
  • 原文地址:https://www.cnblogs.com/8013-cmf/p/12421415.html
Copyright © 2020-2023  润新知