服务扩到 3 个副本后每天九点的日报生成了 3 份,数据库里同一天出现三条汇总,调用方还以为接口重复返回。
一开始怀疑是「锁的过期时间短于任务执行时间」,查了一圈,方向不对。
把日志和配置对完,能解释这个现象的基本就这几处。定时器写在应用内,每个副本各跑一份。少数情况下是没有 leader 选举或分布式锁。
还有一种情况,CronJob 与内置调度同时存在,叠加触发。
从日志确认是哪个副本在跑
kubectl logs -l app=report --since=24h | grep -c 'generate report'
然后改成只有一个实例抢到锁才执行
redis-cli SET lock:report:daily $POD_NAME NX EX 1800
接着把锁续期做到任务结束
python lock_heartbeat.py --key lock:report:daily --ttl 1800
剩下的就是清理当天的重复汇总
python dedupe.py --table daily_report --date today --keep earliest
改完先别撤,确认这几项。当天只有一条汇总记录,三个副本日志里只有一个出现执行标记,其余两个显示未获得锁。
这里还有个坑。应用内定时器在多副本下必然重复,要么交给外部调度,要么用带续期的锁,别只靠一次性抢锁。这类问题最好一次改到位,反复小改反而容易把原因搅混。
