zoukankan      html  css  js  c++  java
  • php多进程单例模式下的 MySQL及Redis连接错误修复

    前几天写了个php常驻脚本,主要逻辑如下

    //跑完数据后休息60秒
    $sleepTime = 60;
    $maxWorker = 10;
    while (true) {
        $htmlModel = new DetailHtmlModel();
        //新抓取的html数目
        $count = $htmlModel->getCount(array(
            array('status', '=', DetailHtmlModel::STATUS_UNDEAL)
        ));
        if ($count > 0) {
            //将抓取的html数据放入队列
            Queue::putHtmlData();
        }
        $queueLength = Queue::getHtmlQueueLength();
        if ($queueLength > 0) {
            //启动的worker数目,限制启动的个数
            $workerCount = min($maxWorker, ceil($queueLength / 10));
            runWorker($workerCount);
            $sleepTime = 60;
        } else {
            //无数据的话每次多停5秒
            $sleepTime += 5;
        }
        unset($htmlModel);
        sleep($sleepTime);
    }

    看代码知道,我根据待处理的数据量启动最多10个的worker去处理数据,每个worker是一个进程,但跑起来后遇到两个错误: 
    一个是mysql的:MySQL server has gone away 
    另一个是redis的:Uncaught exception ‘RedisException’ with message ‘read error on connection’ 

    原因:


    出现MySQL server has gone away 常见的原因就是连接时间超过了mysql设置的wait_timeout值,这时mysql会主动关掉连接,默认是8小时。但是我是启动脚本就出现这个错误,而且使用连接前都先做了ping,不可能是连接超时了,又看了mysql官网对这个错误可能原因的说明(原文)里面有这么一句:

    You can also encounter this error with applications that fork child processes, all of which try to use the same connection to the MySQL server. This can be avoided by using a separate connection for each child process.

    很多公司代码在创建mysql和redis的连接实例时,采用的都是单例模式,我们也一样。也就是说无论外部new了多少实例,只要句柄存在就会被返回,而不是重新创建连接实例。刚好我又启动了多个进程去处理数据,然后每个进程又使用同一个连接实例,就导致了报错 

    解决办法:


    通常只有在cli运行模式下才有可能出现超时的情况,所以在构建mysql单例句柄的key时使用getmypid()加入进程id,这样就能把每个进程使用的连接实例分隔开 
    mysql:

    private static function _getHandleKey($params) {
        //解决多进程会保持同一个连接的错误
        if (PHP_SAPI === 'cli') {
           $params['pid'] = getmypid();
        }
        ksort($params);
        return md5(implode('_' , $params));
    }

    redis也使用同样方法解决问题

  • 相关阅读:
    每次任务 创建 一个 Scheduler,运行完直接shutdown ,同时运行不相互影响.
    get 和 post 的区别
    jq ajax
    h5
    reset
    ajax
    手机端
    IE浏览器下LI的默认高度
    IE FF 支持li:hover,但是ie6不支持,a:hover ul 这种写法是要搭配顶部针对IE6声明用的
    ie7/8卸载工具 降级到IE6
  • 原文地址:https://www.cnblogs.com/gwyy/p/8658329.html
Copyright © 2011-2022 走看看