SQS 的 visibility timeout 设了 30 秒,单条任务实际要跑 90 秒,消息被其他消费者重复取走,同一份报告生成了三遍,下游去重表开始冲突。

一开始怀疑是「失败重投时没有带幂等键」,查了一圈,方向不对。

这类报错背后常见的原因有几处,逐个排除就行。可见性超时按平均耗时设,没有看 P99。还有一种是处理过程中没有续期心跳。

另外,消费者数量多,超时后的消息很快被别人抢走。

量出单条任务的耗时分布

python -c "import json;d=json.load(open('task_lat.json'));print(sorted(d)[-10:])"

接着把可见性超时按 P99 乘 1.5 设置

aws sqs set-queue-attributes --queue-url $QURL --attributes VisibilityTimeout=150

再往下处理中定时续期可见性

python worker.py --extend-every 60 --visibility 150

给消息补幂等键并在写库前去重

python -c "print('idem_key=task_id')"

改完先别撤,确认这几项。同一任务只被执行一次,重复生成报告的条数归零,队列里可见消息数与实际待处理数一致。

补一句。可见性超时不是执行超时,它只决定消息多久后能被别人再取走;长任务必须续期,或者干脆拆成小步骤。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。

作者 9823189