线上服务全挂了,经排查居然是vim的锅?
The following article is from Coder梁 Author 梁唐
一
最近无意间打开了曾经做后端时的笔记,想起来许多往事,挑了一段有意思的,分享给大家。
故事发生的时候我还是一个萌新,啥都不知道,完全听老板和师兄安排。发生的时候是一个周末,周末嘛,自然就开开心心过周末,出去玩耍、约会,吃点好吃的,或者找点好玩的。就在正开心的时候,突然收到一条报警短信,说某某服务器挂了。
我正担心呢,就收到了师兄的消息,他说不要紧,我让隔壁组的同事帮忙查了,应该很快就能好。
我听到师兄这么讲也就安心了,没想到后来整个服务都宕机了,完全无法响应,因此还出了一个P1的故障。一般来说这种级别的故障都有一些很深奥的原因,没想到后来开故障分析会的时候,才知道这次的事故起因非常非常不起眼,出在了大家日常都会使用的vim上。
二
原本第一台机器的宕机并不稀奇,由于OOM。
当时的服务器后端是用Java写的,Java和C++相比最大的区别就是Java有自动垃圾回收机制,而C++只能手动释放内存。
但Java的自动垃圾回收机制也有很多问题,比如JVM的配置不合理,或者是代码写得不够优雅,创建了许多极耗内存的对象,垃圾回收策略来不及处理或者是超过了能够处理的极限,就会引起内存超界的错误。英文是OutOfMemory,简称为OOM。
这种现象在Java后端还挺常见的,可能我们当时的系统也的确不够优雅。原本这个问题并不大,因为集群都有负载均衡策略,一个服务都对应多台机器。哪怕是一台机器挂了,上层的网关做流量分发的时候会自动避开宕机的机器,一样能保证请求都能有响应。
所以一台机器挂了其实没啥问题,我们什么都不做等它自动重启或者是找运维帮忙手动重启都行。要命就要命在找了隔壁组的师兄来排查故障。
这哥们排查故障的时候,非常自然地连上了服务器,然后用vim打开了系统的日志。
就是这一行代码:
vim xxxx.log
三
我当时听到报告的时候也很纳闷,vim打开日志不是天经地义的事情吗,这也会出问题吗?
正常来说当然是不会,但这里有一个隐藏的前提条件,就是vim打开文件时会把文件加载在系统的内存里(显然)。既然是加载在内存里,那么自然是会消耗内存的。这就导致了一个问题,如果这个文件太大,然后又用了vim强行打开,很有可能会导致系统内存耗尽于是崩溃。
这个哥们那天正是遇到了这样的事情,他发现vim打开之后ssh连接断了。他以为是自己的网络出了问题,于是他换了一台机器连接查看日志,于是同样的剧本再次上演。这哥们一口气把所有的服务器都查看了一遍,发现都没反应,他以为是自己的ssh跪了,就汇报说暂时看不了问题,因为ssh跪了。
报告的人也没当回事,因为之前的报警只是挂了一台机器,不会影响服务,也就没当回事。你可能会好奇,后面的机器挂了难道没报警吗?说来惭愧,关于这里的细节我有些记不清了。
我猜想了一下,无非两种可能,一种是报警程序是运行在机器里检测java进程的,java进程挂了能够发现并报警,但如果是机器直接挂了,就没法报警了。第二种可能是报警了,但是他们以为还是之前的问题,于是忽略了。
四
当时这个故事给我触动很大,这也是我至今还能记住这个故事的原因。因为我没有想到,只是使用vim打开一个文件居然还有这样的风险。
那么问题来了,既然vim打开文件有这样的隐患,我们应该怎么办呢?
大概有两种方法,第一种是事先检查。在使用vim打开文件之前,先使用ls命令查看一下文件的大小,如果文件过大则不要直接打开。
检查的命令很简单:ls -lh,ls命令很简单,大家都知道查看目录下文件。这里传入了两个参数,l表示详细信息,包括文件类型、权限、文件大小等。但是这里显示的文件大小是字节数,很难直接看出来有多大,所以我们需要加上一个参数h,我没记错的话,这个参数表示将文件大小转化成人类可识别的形式。
比如我们不加h,得到的结果是这样的:
加上h之后,则是这样的:
这里的文件大小就容易理解多了。
第二种方式是使用tail代替vim查看log,tail的意思是查看文件尾部的内容。它有两个参数非常常用,一个是-n,也就是显示最后n行。
tail -n10 xxx.log
我这里写的就是显示xxx.log文件的最后10行,这里的n也可以省略,写成tail -10也行。
第二个参数是-f,-f的意思是表示循环输出。因为线上的日志往往是不断变更的,因为会有系统一直往当中写入新的日志。我们使用-f,就可以保持同步,将源源不断写入的内容都打印在屏幕上。
并且-f可以和-n一起使用,表示从当前末尾n行开始一直循环输出。
tail -30f xxx.log
自从学会了这两招,再也没有因为使用vim打开巨大日志而导致系统崩溃过。
推荐阅读: