文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2024-04-02 19:55

关注

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


<?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假死的资料请关注编程网其它相关文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯