• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    详解PHP解决守护进程Redis假死

    一、一个简单的守护进程示例

    ?php
    $redis = new \Redis();
    $redis->connect('localhost', 6379);
    $redis->auth('xxxxx'); // Redis 密码如果没有设置为空字符串。
    $redis->select(1);
    
    $queueKey    = 'redis_queue_services_key';     // 业务数据队列。
    $queueIngKey = 'redis_queue_services_ing_key'; // 处理中的队列。
    
    try {
        while (true) {
            $element = $redis->bRPopLPush($queueKey, $queueIngKey, 60);
            if ($element) {
                $data = json_decode($element, true);
                /**
                 *
                 ...... 此处省略业务逻辑 ......
                 *
                 */
            } else {
                usleep(100000); // 睡眠 0.1 秒。
            }
        }
    } catch (\Exception $e) {
        exit("Error:{$e->getMessage()}");
    }

    这段代码我们很容易看懂。

    它就是通过Redis的阻塞方法bRPopLPush循环从 Redis 队列中取出数据并处理。如果没有取到数据就休眠一秒。之所以休眠是为了保证 CPU 能得到充分的利用。因为,我们已经使用了阻塞方法阻塞 60 秒。所以,这个位置休眠与否并不重要。

    当我们的业务出现任何错误,我们通过try catch进行异常捕获然后将错误信息直接输出并退当前脚本。

    博主寒冰第一次编写常驻后台运行的守护进程时,就是如上这种方式写的代码。结果,这段代码运行到 30s 的时候报错了。提示我们 socket 流超时。于是我在这个脚本头部加了如下代码:

    ini_set('default_socket_timeout', -1);

    这样我们的PHP就不会主动段掉我们与 Redis 的 socket 连接了。

    但是,好景不长。过了一段时间,大概半个月吧。运维同学告诉我 Redis 队列的数据出现了未消费的情况。然后,我查看了消费日志。的确没有产生新的消费日志。因为我有一个习惯,每个消费消费的时候都会把成功消费的日志写到文件中。消费失败的也写入日志文件中。这样,我就知道失败的具体原因。

    但是,这次我真的没有发现有任何的错误发生。

    我当时也怀疑过是不是像MySQL一样常时间连接不进行任何操作,服务器端会主动断开连接。但是,MySQL 服务器端主动段掉连接会提示:MySQL server has gone away的错误。但是,我们的 Redis 服务器端没有给我们报任何错误信息呀。

    我们公司用的是阿里云的 Redis 产品。我怀疑是不是 Redis 版本太低造成的这个隐性 BUG。于是,我们将阿里云的 Redis 服务升级到了阿里云支持的最新版本。

    结果还是失败了。我们的 Redis 还是假死了。或者说我们的 Redis 处于伪活状态。

    你认为 Redis 活着,其实它早已经死了。你认为 Redis 死了,但是它却没有死亡的特征。

    最后,我冷静下来。

    我假定此时的 Redis 已经死了。只是没有告诉客户端而已。那么我只需要每次检测一下 Redis 连接是否存活就好了。

    于是,我翻看了 Redis 的 API。发现它提供了一个ping()的方法来检测连接是否存活。

    二、一个不再假死(伪活)的 Redis 常驻进程示例

    ?php
    
    $redis = new \Redis();
    $redis->connect('localhost', 6379);
    $redis->auth('xxxxx'); // Redis 密码如果没有设置为空字符串。
    $redis->select(1);
    
    $queueKey    = 'redis_queue_services_key';     // 业务数据队列。
    $queueIngKey = 'redis_queue_services_ing_key'; // 处理中的队列。
    
    try {
        while (true) {
            $element = $redis->bRPopLPush($queueKey, $queueIngKey, 60);
            if ($element) {
                $data = json_decode($element, true);
                /**
                 *
                 ...... 此处省略业务逻辑 ......
                 *
                 */
            } else {
                $pong = $redis->ping();
                if ($pong != '+PONG') {
                    throw new \Exception('Redis ping failure!', 500);
                }
                usleep(100000); // 睡眠 0.1 秒。
            }
        }
    } catch (\Exception $e) {
        exit("Error:{$e->getMessage()}");
    }

    通过代码对比,我们在第一版代码的基础上加了如下代码:

    $pong = $redis->ping();
    if ($pong != '+PONG') {
        throw new \Exception('Redis ping failure!', 500);
    }

    我们向 Redis 服务器发送ping的时候,服务器会返回+PONG字符串。当然,这个是 Redis 扩展封装过的方法。真正的 ping 是不会有 + 号的。

    当我们每次 ping 的时候,Redis 服务器就会认为我们的 Redis 客户端连接处于存活状态。就不会断掉我们的连接了。

    把代码进行改造之后,假死头痛的问题再也没出现了。

    以上就是详解PHP解决守护进程Redis假死的详细内容,更多关于PHP解决守护进程Redis假死的资料请关注脚本之家其它相关文章!

    您可能感兴趣的文章:
    • thinkphp5redis缓存新增方法实例讲解
    • PHP使用Redis队列执行定时任务实例讲解
    • php基于redis的分布式锁实例详解
    • Thinkphp5+Redis实现商品秒杀代码实例讲解
    • PHP操作Redis常用命令的实例详解
    • php在linux环境中如何使用redis详解
    • php操作redis命令及代码实例大全
    • php之redis短线重连案例讲解
    上一篇:详解PHP接口签名验证
    下一篇:详解PHP多进程消费队列
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    详解PHP解决守护进程Redis假死 详解,PHP,解决,守护,进程,