站点运营

站点运营:定时任务与后台队列自查,别让脚本在高峰抢资源

定时任务和后台队列常常没人过问,问题往往在凌晨出现:任务重叠执行、重活挤在访问高峰、失败没有告警、队列只涨不消。本文给出一份自查思路,从列出所有自动运行的任务开始,逐项检查锁、时间窗口、日志告警和队列参数,把夜间故障挡在发生之前。

站点运营

站点运营:定时任务与后台队列自查,别让脚本在高峰抢资源

不少站点的问题不是出在白天,而是出在凌晨三点:定时任务跑了一半,队列堆了几十万条,数据库连接被占满,第二天早上访客打开页面看到的就是 502。这类故障排查起来很花时间,因为触发它的脚本平时看起来「一直都没事」。花半小时把定时任务和后台队列过一遍,成本很低。

先列出所有会自动跑的东西

自查第一步不是优化,而是搞清楚到底有谁在跑。常见的入口有这几处:

  • 系统的 crontab,包括 root 和各站点用户各自的;
  • systemd timer,容易被忽略,因为它不在 crontab -l 的输出里;
  • 框架自带的任务调度,比如定时命令、计划任务配置;
  • 常驻的队列消费者进程,通常由 supervisor、pm2 一类工具托管;
  • 数据库自身的定时事件、备份脚本、日志轮转。

把这些列成一张表,写清楚:做什么、多久跑一次、大概跑多久、跑的时候占用多少 CPU 和磁盘 IO。很多人第一次做完这张表就会发现,有两三个任务其实是重复的。

最容易踩的四个坑

任务重叠执行

一个任务每 5 分钟跑一次,但偶尔要跑 8 分钟,于是第二轮在上一次还没结束时又启动了,两边同时改同一批数据。解决办法是加锁:用文件锁、Redis 锁或数据库标记,拿不到锁就直接退出,并且记一条日志说明这次被跳过了。

挑错了时间窗口

全量重建索引、生成站点地图、批量压缩图片这类重活,如果排在访问高峰,CPU 和磁盘 IO 被抢走,页面响应就会变慢。把它们挪到流量低谷,并且给任务设一个明确的结束时间,超时就中断,不要放任它一直跑。

失败没人知道

定时任务失败最典型的表现是「安静」。脚本报错退出, cron 把错误邮件发到一个没人看的邮箱,然后就没有然后了。至少要做到三件事:非零退出码写进日志、连续失败触发告警、每天早上一封汇总。

队列只涨不消

队列堆积通常有两个原因:生产者写入速度超过消费者处理速度,或者消费者因为一条坏消息卡住反复重试。要盯的是队列长度随时间的变化曲线,而不是某一时刻的数字。

队列相关的几个参数

  • 并发数:调大不一定更快,先确认下游数据库能不能承受;
  • 重试次数与退避:无限制重试会把一条坏消息放大成几百次请求;
  • 可见性超时:设得太短,同一条消息可能被多个消费者重复处理;
  • 死信队列:处理不了的消息要有地方去,而不是被直接丢掉;
  • 幂等:任务重跑一遍,不应该产生重复数据。

一份可执行的检查清单

  1. 列出全部定时任务,标注频率、耗时和资源占用;
  2. 给每一个会写数据的任务加锁并做幂等处理;
  3. 把重任务移出访问高峰时段;
  4. 确认失败有日志、有告警、有人负责看;
  5. 监控队列长度和消费者进程的存活状态;
  6. 定期清理僵尸进程和过期的锁文件;
  7. 每季度复查一次,任务会随着业务增长悄悄变重。
定时任务和队列不需要做得多复杂,但需要被看见。能在出问题的十分钟内发现它,比事后写一份复盘报告划算得多。