一家做分销的客户出了笔糊涂账:某天所有推广员的佣金都发成了两倍。查了一晚上才发现,服务器从一台扩到两台之后,凌晨的佣金结算任务在两台机器上各跑了一遍。定时任务这种不起眼的东西,出起事故来一点不含糊,后端系统开发里它的坑特别集中。
坑一:任务重复执行
单机时代没人管这个问题,应用一扩容,隐患就冒头。解决办法有两种:简单的做法是配置上指定任务只在一台机器上跑,其余机器跳过;更稳的做法是加分布式锁,任务启动前先抢锁,抢到的执行,没抢到的直接退出,锁本身要设过期时间,防止执行中途崩了导致死锁。那位客户最后选的分布式锁方案,十分钟改完,之后再扩容也不怕。
坑二:失败了没人知道
- 凌晨三点的任务挂了,第二天上午财务发现数据不对才倒查出来,中间隔了七八个小时;
- 规范做法是每个任务结束后检查执行结果,失败立刻发告警到管理员手机,同时自动重试一次;
- 重试要防脏数据:任务内部做到可重入,跑一半断了重新来能接得上,或者先清掉半成品再跑。
告警这件事怎么强调都不过分。定时任务出问题几乎都是悄悄的,没有告警,问题暴露的时间取决于下一个发现数据不对的人,而那个间隔就是损失扩大的时间。
坑三是任务堆叠:上一轮还没跑完,下一轮按计划又启动了,两个实例同时写一张表,数据立刻乱掉。处理办法是加运行标记,上一轮没结束就跳过本轮,或者把执行间隔拉长留足余量。见过一个报表任务从两小时慢慢涨到五小时,没人注意,直到和下一轮撞车才发现,任务耗时是会随着数据量增长悄悄变化的,要定期回头看。
给任务留一份执行档案
每次执行都记下开始时间、结束时间、处理条数、成败结果,存一张表里。排查问题时这份档案就是时间线:哪天慢了、哪天空跑了、哪天数量异常,一眼看穿。成本就是一张日志表,性价比极高。
两条建议:部署架构发生变化时——加服务器、换容器、迁云,第一件事就是复查所有定时任务的执行情况,跑一周的执行日志确认每轮只跑一次;验收系统时让开发方演示任务失败的场景,看告警到没到、重试灵不灵。比格网络给客户做系统交接时,任务清单和执行记录是必查项,这类问题早发现都是小活,晚发现全是事故,定时任务因此成了后端系统开发验收清单上的固定项目。