三台服务器同时变慢,我准备大干一场,结果它们自己好了
三台服务器同时变慢,我准备大干一场,结果它们自己好了
下午三点,监控大屏上的几个指标突然变得不太好看。
三台平时表现还算正常的服务器,CPU 使用率同时开始往上爬。某台服务器的响应时间也开始上升,从平时的 200 毫秒,慢慢爬升到了 800 毫秒。
作为一个在上海工作的普通打工人,看到这种情况,我的第一反应是:要出事。
然后我开始排查。
排查的过程
先看看是什么进程在占用资源。SSH 连上去,top 一看,CPU 占用率最高的是一个平时不怎么注意的定时任务。这个任务的名字挺普通的,叫”数据同步”,跑着 Python 脚本,每小时执行一次。
ps aux | grep 看一下,发现这个进程已经跑了 40 多分钟了。正常情况下,这个脚本应该在 5 分钟内完成才对。为什么跑了 40 分钟?是因为数据量太大了?还是脚本本身出了问题?
先别下结论。继续看。
netstat -tlnp 看看网络连接。不看不知道一看吓一跳,这台服务器上居然有 300 多个对外的连接,而且全部是 TIME_WAIT 状态。这些连接是哪来的?为什么没有正确关闭?
df -h 看看磁盘。磁盘使用率已经接近 75% 了。虽然还没有触及告警线,但这个数字比上周多了 10 个百分点。这 10 个百分点是哪些文件占掉的?
crontab -l 看看定时任务。除了刚才那个”数据同步”,还有两三个其他的定时任务在跑。其中一个任务是”日志清理”,按理说应该每天清理一次,但上次运行记录显示,这个任务已经有两周没跑过了。
一圈查下来,我发现了一个有意思的现象:
所有的症状,都是”历史积累”造成的。
TIME_WAIT 连接堆积,是因为代码里没有正确关闭连接。磁盘使用率上升,是因为日志清理任务没跑。CPU 占用高,是因为那个同步脚本卡住了。
这些不是”今天突然发生的问题”,而是”问题一直存在,只是一直没有被处理”。
换句话说,这些服务器不是”变慢了”,而是”终于慢到可以被察觉了”。
我准备大干一场
既然发现了问题,那就开始修复吧。
方案很清晰:
- 先 kill 掉那个卡住的同步脚本进程
- 清理掉那些 TIME_WAIT 连接
- 手动跑一遍日志清理
- 看看磁盘空间里都是什么大的文件,能删的删,不能删的归档
- 检查代码里的连接关闭逻辑,避免类似问题再次发生
这套方案下来,估计需要一个下午。SSH 连上服务器,改配置文件,重启服务,验证效果——每一步都需要时间,而且每一步都有可能引入新的问题。运维工作的一个特点就是:你以为你在修一个问题,但实际上你可能会制造三个新问题。
正当我准备动手的时候,我看了一眼监控大屏。
等等——CPU 使用率好像在下降?
我再仔细看了一眼。不是错觉。CPU 使用率确实在下降。从刚才的 70% 多,慢慢回落到了 50%,然后是 40%,最后稳定在了 30% 左右——这是平时的正常水平。
我愣了一下。
然后我去查了那个同步脚本的进程。进程还在跑,但 CPU 占用已经降下来了。再等几分钟,进程自己结束了,输出显示同步成功。
我看了看到达时间:16:47。从监控触发到自动恢复,前后大概一个半小时。
它们怎么自己好了?
这个问题让我想了很久。
后来我在查看监控历史数据的时候,发现了一个规律。
过去一个月里,这三台服务器每隔几天就会出现一次 CPU 使用率的”小高峰”。高峰的幅度不大,持续时间不长,一般在半小时到两小时之间就会自动回落。
也就是说,这不是”服务器变慢了”,而是”服务器在以一种固定的节奏运行”,而我之前一直没有注意到这种节奏。
为什么会这样?
我猜测,可能跟业务特点有关。某些业务在每天下午会有一个高峰,在这个高峰期间,定时任务和数据同步会密集执行,导致资源紧张。但高峰过后,任务执行完毕,资源就自动释放了。
这不是系统故障,这是系统的正常波动。
我以为我在处理一个问题,但其实这个问题根本不需要处理。
但我还是做了一些事情
虽然系统自己恢复了,但我还是做了一些事情。
首先,我把这个现象记录了下来。记录内容包括:监控指标的变化规律、可能的原因猜测、后续需要关注的指标。这些记录以后可能用得上——如果下次再出现类似的情况,我就知道这是正常波动,而不是新的问题。
然后,我调整了监控告警的阈值。既然这是一个周期性的正常波动,那就不应该每次都告警。我把 CPU 使用率的告警阈值从 60% 上调到了 75%,把响应时间的告警阈值从 500ms 上调到了 1000ms。
这样一来,除非真的出了问题,否则不会有人被白吵一顿。
我还顺便清理了一下磁盘空间。手动跑了一遍日志清理,把能删的文件删掉,把需要保留的文件做了归档。磁盘使用率从 75% 降到了 58%,又回到了正常水平。虽然这个清理工作对解决今天的问题没有直接帮助,但至少让服务器回到了一个更健康的状态。
最后,我给代码提了一个 MR,在连接使用完毕后加了 close() 调用。这个改动很小,但可以避免 TIME_WAIT 连接堆积的问题。虽然这个问题今天没有造成实际的影响,但作为一个潜在的隐患,还是应该尽早修复。
这些工作加起来,大概花了我一个小时。比原计划的”大干一场”要轻松很多。
感悟
今天的事情让我有几点感悟。
第一,不是所有的问题都需要你去解决。很多”问题”其实是系统的正常波动,是业务规律的一部分。如果你看到一点风吹草动就冲上去,反而可能破坏系统的正常运行。学会观察、学会等待、学会判断”这是不是真的问题”,是运维人员的重要能力。这个道理听起来很简单,但真正做到并不容易。我今天差点就”大干一场”了,如果不是最后关头看了一眼监控大屏,可能就真的动手了。动手之后会发生什么?不知道。可能能解决问题,也可能引入新问题。所以,养成”先观察再行动”的习惯非常重要。
第二,监控系统有时候会制造焦虑。当所有指标都在监控屏幕上跳动的时候,你很难判断哪些是需要立即处理的,哪些是可以先放一放的。这就需要你有足够的经验来判断:哪些告警是真的告警,哪些只是噪声。这不是靠培训能学会的,是靠经验积累的。见过足够多的”虚惊一场”,你才能在遇到真正的告警时保持冷静。监控系统的目的本来是减轻我们的工作负担,但如果配置不当,它反而会制造更多的负担——每天被大量无效告警轰炸,迟早会麻木,到时候真正的问题反而被忽视了。
第三,不要被”准备大干一场”的冲动支配。当我看到三台服务器同时变慢的时候,我的第一反应是”这次要大干一场了”。我甚至已经开始在脑子里规划行动方案:先排查网络,再看进程,然后检查配置,最后可能还要重启服务。但实际上,这个问题根本没有我想的那么严重。回头想想,如果我真的按照原计划大干一场,花了一个下午做了一堆修改,可能反而会引入新的问题。修改意味着风险,不改反而是安全的。很多时候,保持现状、不做改变,是最安全的选择。除非你确定改变带来的收益大于风险,否则不要轻易行动。
第四,学会从历史数据中找规律。如果不是调出过去一个月的监控历史,我根本不会发现这是周期性波动,而不是突发故障。这种从历史数据中找规律的能力,是监控分析的核心。有时候,解决问题的方法不是”做点什么”,而是”看懂它在干什么”。看监控大屏,不能只看当前数据,要看历史趋势。这个习惯需要在日常工作中慢慢培养。
第五,打工人的成就感不一定来自”解决了大问题”。今天的成就感,来自”没有冲动地去解决问题”。有时候,知道”不要做什么”,比知道”要做什么”更重要。能在关键时刻保持克制,是一件很难的事情。但正因为难,才值得记录。
第六,”历史积累”的问题往往是最容易被忽视的问题。今天我发现的所有问题,归根结底都是”历史遗留”——定时任务没跑、连接没有关闭、日志没有清理。这些问题不会突然爆发,但会慢慢积累,等到你发现的时候,可能已经很严重了。定期清理”历史遗留”,是一个好习惯。建议每周或每月安排一次”系统清理日”,专门处理这些看起来不紧急但长期来看很重要的事情。
第七,做运维要有”与不确定性共处”的能力。今天的情况是:三台服务器同时变慢,原因不明,可能是什么也不知道。我可以大干一场,也可以什么都不做。最终我什么都没做,问题自己好了。这种”不确定性”在运维工作中非常常见。你永远不可能掌握所有信息,也不可能预测所有结果。学会与不确定性共处,学会在信息不完整的情况下做决策,是运维人员的必修课。
第八,沟通和记录同样重要。今天虽然没做太多实际的工作,但我做了大量的记录和沟通。我把监控数据的异常报告发给了开发团队,提醒他们检查代码里的连接关闭逻辑。我在群里同步了处理进展,让相关的人知道事情在可控范围内。这些看起来是”软工作”,但实际上非常重要。它建立了团队之间的信任,也留下了可供追溯的记录。运维工作不只是技术工作,也是沟通和协调工作。
工作方式的反思
今天的事情还让我对”打工人如何工作”这件事有了一些新的思考。
第一,不要急于行动,先观察。遇到问题时,不要急于动手。先观察一下情况,看看是不是真的需要处理。很多时候,问题会自己消失,或者问题本身就不是问题。冲动的后果往往比什么都不做更糟糕。
第二,多角度看问题。今天我从一个角度看,发现了很多”问题”。但换了一个角度(历史趋势)看,发现这些”问题”都不是问题。这种多角度看问题的方式,值得在日常工作中推广。
第三,相信数据,不要相信感觉。今天的”感觉”告诉我三台服务器同时变慢很危险,应该立即处理。但数据告诉我,这只是周期性波动,不需要处理。相信数据,而不是感觉,是运维人员的基本素养。
第四,留有余地,不要过度干预。如果今天我按照原计划”大干一场”,可能真的会解决问题,但也可能引入新的问题。很多时候,保持现状、不做改变,是最安全的选择。除非你确定改变带来的收益大于风险,否则不要轻易行动。
第五,记录和分享是工作的一部分。今天的事情,让我意识到记录和分享的重要性。如果不是有记录历史的习惯,我可能早就忘记了今天发生的事情。通过记录,我可以回顾自己的决策过程,检视有没有做错什么。通过分享,可以让其他人从我的经历中学习,避免重复踩坑。
第六,告警阈值不是一成不变的。随着对系统的理解加深,告警阈值应该动态调整。今天我把阈值调高了,因为我知道某些”异常”其实是正常波动。如果一直用最初的阈值,每天都会被白吵,迟早会麻木。合理配置告警阈值,是减少无效工作的重要手段。
第七,定期回顾很重要。如果不是今天这个机会,我可能永远不会去查看过去一个月的监控历史。正是这次回顾,让我发现了周期性波动的规律。定期回顾应该成为工作的一部分,比如每周花半小时看看本周的监控趋势,可能会有意想不到的发现。
关于这次”虚惊一场”的复盘
严格来说,这次不算”虚惊一场”,因为告警是真实的——服务器确实变慢了。但它也不是真正的故障,因为系统自己恢复了。
这种情况下,应该如何复盘?
首先,确认是否有遗漏的问题。虽然系统自己恢复了,但”为什么会变慢”这个问题还没有得到彻底的解答。是业务高峰导致的正常波动?还是某个隐藏的问题在悄悄积累?目前我的猜测是业务高峰,但这个猜测需要进一步验证。
其次,检查告警配置是否合理。如果系统自己能在 1.5 小时内恢复正常,那说明这个问题本身不需要人工介入。但它还是触发了告警,说明告警阈值设置得太低了。调整阈值,让真正需要人工介入的问题触发告警,是接下来的工作。
第三,思考是否有预防措施可以做。即使问题会自己恢复,是否有办法让它恢复得更快?或者,是否有办法让它根本不发生?这些问题值得思考,但不一定有答案。
第四,也是最重要的一点:不要因为”没有出事”就认为”之前的担心是多余的”。在运维工作中,任何一次”虚惊一场”都可能是上帝在提醒你:这个问题值得注意,下次可能就不会这么幸运了。今天系统自己恢复了,下次可能就不会恢复。
所以,即使今天什么都没做,我还是在监控里增加了对这个周期性波动的关注。如果下次它变得更严重了,我会第一时间知道。
结尾
好了,今天就写到这里。
三台服务器同时变慢,我准备大干一场,结果它们自己好了。这个故事听起来像是一个笑话,但它反映的是运维工作中的一种常见困境:当问题出现的时候,你如何判断它是真正的问题,还是正常波动?
这个问题没有标准答案。
有些告警是真的,需要立即处理;有些告警是噪声,可以忽略。区分它们需要经验,需要对系统的深入了解,需要从历史数据中找规律的能力。
今天的我,比昨天的我,更接近正确答案。明天的我,会比今天更接近。
这就是打工人成长的方式。不是什么惊天动地的大事,就是这样一点一点地积累,一点一点地进步。
明天继续加油吧。
作者:小六,一个今天准备大干一场结果什么都没干成的打工人