客户的业务系统有个规矩:每天凌晨三点跑批,把前一天的数据汇总、对账、生成报表。这个跑批跑了两年多,一直挺稳,结果上个月开始,隔三差五就失败一次,报错时间还特别固定——都是凌晨三点前后。

客户很急,因为跑批失败意味着第二天早上领导看不到报表,他们就得挨骂。我们远程上去看了好几次,日志显示任务确实启动了,但走到一半就报"任务窗口已过"或者"数据时间不匹配",然后就退出了。

一开始我们怀疑是数据库连接问题。跑批要连一个老库,有时候连接池满了会超时。查了连接数、慢查询、锁等待,都正常。又怀疑是 crontab 被谁改过,看了执行记录,触发时间没毛病。还怀疑过是不是有人在那个时间点手动跑过任务,把数据状态搞脏了,查了操作审计,也没有。

折腾了快一周,客户那边都有点不耐烦了,说你们到底行不行。那天我实在没辙,就坐在那盯着服务器发呆,顺手敲了个 date,想看看当前时间对不对——结果发现服务器时间比北京时间快了六分多钟。

我当时就愣住了。赶紧又确认了一遍:date、timedatectl、跟标准时间对,确实是快了 6 分 20 秒左右,而且这个差值不是固定的,我隔半小时再看,变成了 6 分 40 秒——它还在越走越快。

这就对上了。他们跑批任务里有个逻辑:任务启动后先判断"当前时间是否在凌晨 2:50 到 3:10 的窗口内",不在就认为自己是误触发,直接退出。服务器时钟越走越快,跑到凌晨三点那会儿,实际可能已经 3:06 了,任务一启动,拿本地时间一算——超过 3:10 了,窗口已过,直接自杀。所以报错时间才那么固定,全卡在三点前后那几分钟里。

为什么时钟会漂这么快?查了下,这台机器是台老物理机,CMOS 电池基本没电了,而且系统里压根没配 NTP——chronyd 没装,ntpdate 也没人跑过。机器平时不重启还好,一重启时间就从 BIOS 那个快没电的电池里读,越跑越偏。之前两年没事,大概率是以前有人手动校过时,或者机器没跑批这么敏感的逻辑,现在跑批加了这个窗口判断,问题就爆出来了。

处理倒简单:装上 chrony,配上时间源,强制同步一次,然后观察。第二天凌晨跑批就正常了,连着看了四五天,时钟偏差稳定在几十毫秒以内,再没出过岔子。

后来我跟客户说,服务器时间这种最基础的东西,反而是最容易漏的。业务逻辑越复杂,越依赖一个"可信的时间"。配好 NTP、加个时间偏差告警,比啥都强。他们点头,说这周就安排把所有服务器都查一遍。

写下来是想提醒自己:排查别光盯着业务层,有时候 date 一下,比看一天日志都管用。