ThinkPHP延迟队列监控需五步:一查Redis ZSet数据完整性;二检消费者守护进程健康;三比任务投递与执行时间差;四启失败队列与结构化日志;五建Prometheus+Grafana时效性仪表盘并设告警。
如果您在ThinkPHP中使用延迟队列(如订单超时取消、消息延时推送等场景),但发现任务未按预期时间执行或出现积压、丢失、重复消费等问题,则很可能是延迟调度机制失效或监控缺失所致。以下是监控ThinkPHP队列延迟状态的具体方法:
一、检查Redis延迟队列ZSet数据完整性
ThinkPHP配合think-queue扩展使用Redis实现延迟队列时,所有延迟任务均以时间戳为score存入有序集合(ZSet)。监控该ZSet的结构与内容,可直接判断延迟任务是否成功入队及是否到期未被消费。
1、确认延迟队列使用的Redis数据库索引与配置一致,例如config/queue.
php中select值为5,则连接对应db5。
2、执行redis-cli命令查询延迟队列键名(默认为queues:default_delay,若自定义队列名则为queues:your_queue_name_delay):redis-cli -n 5 zcard queues:default_delay,查看当前待处理延迟任务总数。
立即学习“PHP免费学习笔记(深入)
”;
3、获取最早到期的3条任务:
redis-cli -n 5 zrangebyscore queues:default_delay -inf $(date +%s) LIMIT 0 3,验证是否含有效任务数据。
4、检查是否存在大量远期score任务(如score > 当前时间戳+86400),表明任务投递时间计算错误或业务逻辑异常。
二、部署延迟任务消费守护进程健康检测
延迟队列依赖常驻消费者进程轮询ZSet并执行到期任务。若进程崩溃、卡死或未启用--daemon模式,将导致延迟任务堆积且无告警。需对消费者运行状态实施主动探测。
1、编写检测脚本读取消费者进程PID文件(如runtime/queue/consumer.pid),确认进程ID是否存在且对应进程仍在运行。
2、向消费者进程发送信号检测响应能力:
kill -0 $(cat runtime/queue/consumer.pid) 2>/dev/null && echo "alive" || echo "dead"。
3、检查消费者日志中最近10分钟是否持续输出“正在拉取到期任务”或“处理订单XXX超时”类日志行,缺失则说明进程停滞。
4、使用ps aux | grep "queue:work.*--queue=default_delay"确认实际运行参数是否包含目标延迟队列名及--daemon标识。
三、采集并比对任务投递时间与实际执行时间差
延迟精度依赖于投递时指定的时间戳与消费者轮询周期的配合。通过记录任务生命周期关键时间点,可量化延迟偏差,识别系统性延迟原因。
1、在调用Queue::later()前,记录当前毫秒级时间戳并写入任务数据:$data['enqueue_time_ms'] = round(microtime(true) * 1000)。
PHP 8.5.5 PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。
下载
2、在Job类fire()方法开头,再次记录执行时间戳:
$exec_time_ms = round(microtime(true) * 1000)。
3、计算偏差值:$delay_deviation = $exec_time_ms - ($data['enqueue_time_ms'] + $expected_delay_ms),若绝对值持续超过500ms,需检查Redis响应延迟或消费者轮询间隔设置。
4、将偏差值写入独立监控表或上报至Prometheus指标:queue_delay_deviation_milliseconds{job="order_timeout"}。
四、启用think-queue内置失败队列与重试日志追踪
延迟任务在消费阶段若因异常中断,可能被重复投递或静默丢弃。启用失败队列机制并结合结构化日志,可定位延迟失败根因。
1、确保config/queue.php中failed配置项已启用,例如'driver' => 'database'且table指向failed_jobs表。
2、在Job类failed()方法中,强制记录完整上下文:
\think\facade\Log::error('Delay job failed', ['job' => get_class($this), 'data' => $data, 'exception' => $e->getMessage()])。
3、定期执行SQL查询:SELECT * FROM failed_jobs WHERE failed_at > DATE_SUB(NOW(), INTERVAL 1 HOUR) AND connection LIKE '%redis%',筛选近一小时延迟任务失败记录。
4、检查failed_jobs表中attempts字段是否大于1且maxTries配置为3,若持续达到上限,表明任务存在不可恢复依赖故障。
五、构建延迟任务时效性仪表盘(Redis+Prometheus+Grafana)
将Redis ZSet元数据与消费者运行指标暴露为Prometheus可采集端点,实现延迟任务时效性可视化,及时发现趋势性延迟恶化。
1、在ThinkPHP控制器中新增/metrics/delay_queue接口,返回如下指标文本:queue_delay_pending_total{queue="default_delay"} $(redis-cli -n 5 zcard queues:default_delay)。
2、添加指标queue_delay_oldest_seconds:计算ZSet中最小score与当前时间差,queue_delay_oldest_seconds{queue="default_delay"} $(($(date +%s) - $(redis-cli -n 5 zrange queues:default_delay 0 0 WITHSCORES | awk '{print $2}')))。
3、配置Prometheus抓取该端点,采集频率设为15秒;在Grafana中创建面板,绘制queue_delay_oldest_seconds随时间变化曲线。
4、设置告警规则:当queue_delay_oldest_seconds > 300 持续5个周期,触发企业微信/钉钉通知运维人员。
