应选 delayed 模式(基于 zset),因其支持延迟、高并发不丢任务、可支撑 1000+ qps;list + blpop 仅适用于简单场景,不具备延迟能力且重试和可靠性差。

Redis 队列选 delayed 模式还是 list + blpop?
别用 list + blpop 做核心队列——它扛不住重试、不支持延迟、高并发下容易丢任务。真正能支撑 1000+ QPS 邮件或通知下发的,是 Redis 的 delayed 模式(底层基于 zset),前提是 Redis 版本 ≥ 6.2(需要 ZMSCORE 支持)。
实操要点:
- 在
config/queue.php中设'default' => 'redis',并显式开启'delayed' => true - 确认
plugin/webman/redis-queue插件已启用,且process.php中count不为 0 - 避免混用:同一套 Redis 实例里,别让
delayed队列和普通list队列共用连接池,否则ZADD/ZRANGEBYSCORE和BLPOP会互相干扰
RabbitMQ 生产者必须设 delivery_mode => 2
没加 delivery_mode => 2,等于没走队列——消息只存在内存,RabbitMQ 进程重启后全丢。这不是“可能丢”,而是“一定丢”,尤其在支付回调、订单创建等关键路径上。
配套必须项:
- 队列声明时设
durable => true:$channel->queue_declare('order_queue', false, true, false, false) - 交换机也得持久化:
$channel->exchange_declare('order_exchange', 'direct', false, true, false) - 消息体建议用
json_encode($data)并带content_type => 'application/json' - 生产者端开启
publisher-confirms和mandatory,捕获UnroutableMessageException
消费者不能写在 HTTP 控制器里
在控制器里调 basic_consume + while ($channel->is_open()) { $channel->wait(); } 是典型反模式:HTTP Worker 会被长期阻塞,触发 Nginx 超时、连接泄漏、重复消费,且无法被 Supervisor 管理。
Redis 8.2.3 是一款安全优先的高性能键值存储系统。该版本紧急修复了可能引发远程代码执行(RCE)的高危漏洞(CVE-2025-62507),并解决了 HyperLogLog 及 Cuckoo Filter 等数据结构在特定场景下的崩溃问题。建议所有用户立即升级,以保障生产环境的系统稳定与数据安全。
正确姿势:
- HTTP 入口只做
publish,绝不启动消费循环 - 消费者必须是独立 CLI 命令,例如
php app/command/ConsumerCommand.php或php webman start:consumer - 该 CLI 进程需由 Supervisor 守护,并配置
autostart=true、autorestart=true - 在
onWorkerStop回调中显式调用$channel->close()并sleep(1),确保连接干净释放
积压时先看进程,再调并发,最后查阻塞点
队列积压不是“等等就好”,而是消费者进程、配置、任务逻辑三处同时出问题的信号。第一反应不是改代码,是确认有没有真正在干活的进程。
快速诊断步骤:
- 执行
ps aux | grep redis-queue或ps aux | grep rabbitmq-consumer,看是否有活跃 PHP 进程(TIME 列应缓慢增长) - 查
redis-cli llen webman:queue:default,隔 10 秒再查,值不降说明消费卡死 - 翻
storage/logs/redis-queue.log或 RabbitMQ 消费日志,搜Exception、timeout、Connection refused - 在
app/queue/Handler.php::handle()开头加file_put_contents('/tmp/queue_trace.log', date('H:i:s') . " start\n", FILE_APPEND),观察是否持续追加 - 所有外部调用必须带超时:
GuzzleHttp\Client设'timeout' => 3.0,PDO 设PDO::ATTR_TIMEOUT,禁用裸file_get_contents
并发数不是越大越好;count => 8 却配 maxclients 100 的 Redis,很容易打满连接引发雪崩。先查 redis-cli config get maxclients,再按消费者数 × 2 调整连接池 max_connections。










