作业队列与分发模型
作业队列把任务的产生与执行解耦:生产者只写入任务描述,执行者按自身容量主动拉取并处理。相比直接调用,它带来三个能力:削峰(生产者不必等执行者)、弹性(执行者数量可增减)、故障隔离(执行者崩溃任务仍在队列中)。代价在于投递语义:多数队列提供「至少一次」投递,任务可能被重复执行,也可能因处理超时被重新投递,因此消费端必须幂等,并且可见性超时必须大于任务的最坏耗时。
基本信息
| 核心概念 | 队列、消费者、可见性超时、确认(ack)、死信队列、优先级 |
|---|---|
| 投递语义 | 至少一次(常见)、至多一次、恰好一次(成本高,通常靠幂等等效实现) |
| 常见实现 | RabbitMQ、Kafka、Redis 列表或 Stream、云平台消息队列、数据库表当队列 |
| 关键要求 | 消费者幂等、超时正确、队列容量有上限与告警 |
典型使用场景
- 批量任务的执行端需要按负载水平扩展
- 上游突发产生大量任务而执行端容量有限
- 长任务需要独立重试,不阻塞上游流程
- 多类任务共用执行池,需要优先级区分
- 跨系统解耦,生产端不必了解执行细节
投递与消费示意
投递与消费示意
# 生产者:只投递任务描述,不等待执行结果
enqueue --queue batch --payload '{"host":"h1","action":"restart"}'
# 消费者:拉取、处理、确认;失败则拒绝(进入重试或死信)
task=$(dequeue --queue batch --visibility-timeout 600)
process "$task" && ack "$task" || nack "$task"
# 数据库表当队列:用状态字段保证至少一次投递下的幂等
# UPDATE tasks SET state='running', worker=:w WHERE id=:id AND state='pending';关键概念与失配后果
| 概念 | 含义 | 失配后果 |
|---|---|---|
| 可见性超时 | 处理期间任务对他人不可见,超时后重新投递 | 短于任务耗时会引发重复执行 |
| 确认 ack | 消费者显式告知处理完成 | 未确认的任务被反复重投 |
| 死信队列 | 多次失败后转入的隔离队列 | 无人查看则失败任务永久积压 |
| 优先级 | 高优任务先被取走 | 低优任务可能长期饥饿 |
| 容量上限 | 积压的最大深度 | 无上限会耗尽存储或内存 |
在「至少一次」投递模型下,重复执行是设计内的正常现象而不是异常。消费端通过幂等键、状态位或唯一约束消除重复影响,比追求恰好一次投递更现实也更可靠。
可见性超时必须大于任务的最坏耗时。设置过短会让长任务被重复投递,短时间内在多个执行者上并发运行,对目标系统形成叠加冲击。