webman Redis消息队列组件 redis-queue 大批量失败

shixiaofei

Redis消息队列组件 redis-queue 大批量失败

问题出现场景:
一次性插入20000条消费信息 , 消息队列 进程100 , 队列处理接近8000-10000 的条数的时候 , 就会出现报错

错误如下:


/data/web/webman/vendor/workerman/redis/src/Client.php:305
Stack trace:
#0 /data/web/webman/vendor/workerman/workerman/Events/Select.php(232): Workerman\Redis\Client->Workerman\Redis\{closure}()
#1 /data/web/webman/vendor/workerman/workerman/Events/Select.php(281): Workerman\Events\Select->tick()
#2 /data/web/webman/vendor/workerman/workerman/Worker.php(2430): Workerman\Events\Select->loop()
#3 /data/web/webman/vendor/workerman/workerman/Worker.php(1554): Workerman\Worker->run()
#4 /data/web/webman/vendor/workerman/workerman/Worker.php(1384): Workerman\Worker::forkOneWorkerForLinux(Object(Workerman\Worker))
#5 /data/web/webman/vendor/workerman/workerman/Worker.php(1358): Workerman\Worker::forkWorkersForLinux()
#6 /data/web/webman/vendor/workerman/workerman/Worker.php(542): Workerman\Worker::forkWorkers()
#7 /data/web/webman/start.php(156): Workerman\Worker::runAll()
#8 {main}Workerman\Redis\Exception: Workerman Redis Wait Timeout (10 seconds) in /data/web/webman/vendor/workerman/redis/src/Client.php:305
Stack trace:
#0 /data/web/webman/vendor/workerman/workerman/Events/Select.php(232): Workerman\Redis\Client->Workerman\Redis\{closure}()
#1 /data/web/webman/vendor/workerman/workerman/Events/Select.php(281): Workerman\Events\Select->tick()
#2 /data/web/webman/vendor/workerman/workerman/Worker.php(2430): Workerman\Events\Select->loop()
#3 /data/web/webman/vendor/workerman/workerman/Worker.php(1554): Workerman\Worker->run()
#4 /data/web/webman/vendor/workerman/workerman/Worker.php(1384): Workerman\Worker::forkOneWorkerForLinux(Object(Workerman\Worker))
#5 /data/web/webman/vendor/workerman/workerman/Worker.php(1358): Workerman\Worker::forkWorkersForLinux()
#6 /data/web/webman/vendor/workerman/workerman/Worker.php(542): Workerman\Worker::forkWorkers()
#7 /data/web/webman/start.php(156): Workerman\Worker::runAll()
#8 {main}

redis 性能截图:

有没有大佬帮忙给看下问题

阅读 952
2个回答

walkor

workerman/redis 是异步的,当有大量redis请求要发给redis时,请求会放在进程一个排队里,然后一个一个发给redis。
当redis处理不过来时,队列里的数据会积压,如果队列里有请求超过10秒还没发送给redis处理,就会报Workerman Redis Wait Timeout (10 seconds)

如果消量很大,可以用redis扩展来发送,它是同步的。参考 http://doc.workerman.net/components/workerman-redis-queue.html 里 在非workerman环境向队列发送消息 部分使用redis扩展发送队列消息

  • shixiaofei 2021-05-21

    感谢感谢! 我看下解决方法!

  • shixiaofei 2021-05-21

    大佬 , 帮忙看下我下方的回复贴内容 是否 可行呢

shixiaofei


通过查看代码超时时间 设置默认为 10S , 增加了配置文件

'wait_timeout' => 20 //超时20秒

最起码能解决快速超时 , 但是 插入效率不是改变 , 但是不知道超时 时间过长会不会对程序稳定性会不会有影响呢

还有其他方案 , 单批次插入 特定条数 , 比如说 10000 条, 立即重启下次 计时器 , 会不会是可行的?

以下是队列插入逻辑源码:

foreach ($this->_queue as $key => $queue) {
                if ($first_queue && $ignore_first_queue) {
                    $first_queue = false;
                    continue;
                }
                if ($time - $queue[1] > $timeout) {
                    $has_timeout = true;
                    unset($this->_queue[$key]);
                    $msg = "Workerman Redis Wait Timeout ($timeout seconds)";
                    if ($queue[2]) {
                        $this->_error = $msg;
                        \call_user_func($queue[2], false, $this);
                    } else {
                        echo new Exception($msg);
                    }
                }
            }

如果改为:

foreach ($this->_queue as $key => $queue) {
                if ($first_queue && $ignore_first_queue) {
                    $first_queue = false;
                    continue;
                }
                if ($time - $queue[1] > $timeout) {
                    //直接return , 也许需要等下有 Client::send 才能重新激活
                    return ;
                }
            }

是否可行 , 还未测试

  • walkor 2021-05-21

    不需要超时的话把 wait_timeout 调成很大的值就好了。

  • shixiaofei 2021-05-21

    好的好的