站点运营

站点运营:定时任務與後台队列自查,別让脚本在高峰抢资源

定时任務和後台队列常常没人過問,問题往往在凌晨出現:任務重叠执行、重活挤在訪問高峰、失敗没有告警、队列只涨不消。本文给出一份自查思路,從列出所有自動執行的任務開始,逐項检查鎖、時間窗口、日誌告警和队列參數,把夜間故障挡在發生之前。

站点运营

站点运营:定时任務與後台队列自查,別让脚本在高峰抢资源

不少站点的問题不是出在白天,而是出在凌晨三点:定时任務跑了一半,队列堆了几十萬條,資料库连接被占满,第二天早上訪客打開頁面看到的就是 502。這類故障排查起来很花時間,因為触發它的脚本平时看起来「一直都没事」。花半小时把定时任務和後台队列過一遍,成本很低。

先列出所有會自動跑的東西

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

  • 系統的 crontab,包括 root 和各站点用戶各自的;
  • systemd timer,容易被忽略,因為它不在 crontab -l 的輸出里;
  • 框架自带的任務調度,比如定时命令、計划任務配置;
  • 常驻的队列消費者進程,通常由 supervisor、pm2 一類工具托管;
  • 資料库自身的定时事件、备份脚本、日誌轮轉。

把這些列成一張表,寫清楚:做什么、多久跑一次、大概跑多久、跑的时候占用多少 CPU 和磁盘 IO。很多人第一次做完這張表就會發現,有两三個任務其實是重复的。

最容易踩的四個坑

任務重叠执行

一個任務每 5 分钟跑一次,但偶尔要跑 8 分钟,于是第二轮在上一次還没結束时又啟動了,两邊同时改同一批資料。解决办法是加鎖:用文件鎖、Redis 鎖或資料库标记,拿不到鎖就直接登出,並且记一條日誌說明這次被跳過了。

挑错了時間窗口

全量重建索引、生成站点地图、批量压缩图片這類重活,如果排在訪問高峰,CPU 和磁盘 IO 被抢走,頁面响應就會變慢。把它們挪到流量低谷,並且给任務设一個明确的結束時間,超时就中断,不要放任它一直跑。

失敗没人知道

定时任務失敗最典型的表現是「安静」。脚本报错登出, cron 把错誤邮件發到一個没人看的信箱,然後就没有然後了。至少要做到三件事:非零登出碼寫進日誌、连續失敗触發告警、每天早上一封匯總。

队列只涨不消

队列堆积通常有两個原因:生产者寫入速度超過消費者處理速度,或者消費者因為一條坏消息卡住反复重试。要盯的是队列長度随時間的變化曲线,而不是某一时刻的數字。

队列相關的几個參數

  • 並發數:調大不一定更快,先確認下游資料库能不能承受;
  • 重试次數與退避:無限制重试會把一條坏消息放大成几百次請求;
  • 可见性超时:设得太短,同一條消息可能被多個消費者重复處理;
  • 死信队列:處理不了的消息要有地方去,而不是被直接丢掉;
  • 幂等:任務重跑一遍,不應该产生重复資料。

一份可执行的检查清單

  1. 列出全部定时任務,标注频率、耗时和资源占用;
  2. 给每一個會寫資料的任務加鎖並做幂等處理;
  3. 把重任務移出訪問高峰时段;
  4. 確認失敗有日誌、有告警、有人负责看;
  5. 监控队列長度和消費者進程的存活狀態;
  6. 定期清理僵尸進程和過期的鎖文件;
  7. 每季度复查一次,任務會随着业務增長悄悄變重。
定时任務和队列不需要做得多复杂,但需要被看见。能在出問题的十分钟内發現它,比事後寫一份复盘报告划算得多。