这篇文章将介绍一个发生在我们网络环境中的真实案例。问题发生在某个推广期,对我们线上集群影响比较大。本文简要回顾这个问题。为了方便大家理解,实际排查和解决过程可能与本文描述的不完全一样,但思路是一致的。问题流程某个推广期间,某在线应用突然出现大量告警,提示磁盘使用率过高,一度达到80%以上。这种情况下,我们第一时间登录线上机查看线上机的磁盘使用情况。使用命令:df查看磁盘使用情况。$dfFilesystem1K-blocksUsedAvailableUse%Mountedon/6291456058911440400312093%//dev/sda26291456058911440400312093%/home/admin发现机器的磁盘消耗真的很严重,因为促销期间有很多请求,所以我们首先开始怀疑日志太多了。导致磁盘耗尽。这是一个背景插入。我们的在线机器配置了自动日志压缩和清理。当单个文件达到一定大小,或者机器内容达到一定阈值时,会自动触发。不过大促当天并没有触发日志清理,导致一时间机器盘被耗尽。经过排查,我们发现该应用程序的某些日志文件占用了大量的磁盘空间,并且还在不断增加。du-sm*|sort-nr512service.log.20201105193331256service.log428service.log.20201106151311286service.log.20201107195011356service.log.20201108155838du-sm*|sort-nr:统计当前目录下文件的大小,并按照大小排序大小及手术经过与同学沟通后,我们决定进行紧急处理。第一种方法是手动清理日志文件。运维同学登录服务器后,手动清理一些不太重要的日志文件。rmservice.log.20201105193331但是执行cleanup命令后,发现机器上的磁盘占用并没有减少,而且还在增加。$dfFilesystem1K-blocksUsedAvailableUse%Mountedon/6291456058911440400312093%//dev/sda26291456058911440400312093%/home/admin于是开始排查日志删除后内存空间没有释放的原因。通过命令,我们发现有一个进程还在处理读取的文件。lsof|grepdeletedSLS11526root3rREG253,02665433605104181296/home/admin/****/service.log.20201205193331(deleted)lsof|grepdeleted的作用是查看所有打开的文件,检查后过滤掉删除的文件,这个过程是连续从机器读取日志内容的SLS进程。SLS是阿里的日志服务,提供一站式的数据采集、清洗、分析、可视化和告警功能。简单来说,它会收集服务器上的日志,持久化,然后提供给查询分析。我们的线上日志是通过SLS收集的,所以通过分析发现磁盘空间没有释放,这与SLS的日志读取有关。至此,问题已经基本定位,下面插话原理,介绍一下背后的背景知识。背景知识在Linux系统中,文件的删除是由链接数来控制的。只有当一个文件没有任何链接时,该文件才会被删除。一般来说,每个文件都有两个链接计数器:i_count和i_nlink,也就是说:在Linux系统中只有当i_nlink和i_count都为0时,文件才会被删除。i_count表示当前文件用户(或调用)数,i_nlink表示媒体连接数(硬链接数);可以理解为i_count是内存引用计数器,i_nlink是磁盘引用计数器。当一个文件被进程引用时,对应的i_count数会增加;当创建文件的硬链接时,相应的i_nlink数会增加。在Linux或Unix系统中,通过rm或文件管理器删除一个文件只是将其从文件系统的目录结构中解除链接,实际上减少了磁盘引用计数i_nlink,但并没有减少i_count的数量。如果某个文件正在被某个进程调用,则用户使用rm命令“删除”该文件。此时无法使用ls等文件管理命令找到该文件,但并不代表该文件就真的从磁盘中删除了。.因为还有一个进程在正常运行,读取或者写入文件,也就是说文件并没有真正被“删除”,所以磁盘空间会一直被占用。而我们网上的问题就是这个原理,因为有进程在操作日志文件,所以rm操作并没有真正删除文件,所以磁盘空间没有释放。解决问题在了解了上面的在线问题现象和相关背景知识之后,我们就可以想办法解决这个问题了。也就是想办法杀掉SLS进程对日志文件的引用,才能真正删除文件,真正释放磁盘空间。kill-911526$dfFilesystem1K-blocksUsedAvailableUse%Mountedon/62914560503316481258291280%//dev/sda262914560503316481258291280%/home/admin特别提醒,在执行kill-9之前,一定要考虑执行的后果是什么可以参考,服务器执行kill-9、第二天就被告知不要来了!后来我们查看磁盘,发现这个问题主要有两个原因:1、在线日志太多,打印太频繁。2、SLS日志拉取速度太慢经过深入分析,我们发现这个应用打印了大量的进程日志。最初打印日志是为了方便排查线上问题,或者是为了数据分析。但是大促期间,日志量激增,导致磁盘空间使用量暴涨。另外,由于该应用与其他几个大型应用共享一个SLS工程,导致SLS拉取速度变慢,无法终止进程。之后,我们也总结了一些改进的项目。对于第二个问题,我们拆分了应用的SLS配置,独立管理。对于第一个问题,就是在推广期间引入日志降级策略。一旦磁盘满了,日志就会降级。关于日志降级,我开发了一个通用的工具,就是动态推送日志级别,通过配置动态修改在线日志输出级别。并将此配置的修改配置到我们的计划平台,在推广期间进行常规或应急计划处理,避免出现该问题。日志降级工具的开发思路和相关代码将在下一篇文章中与大家分享。想过每一次大促之后,我们在回顾市场的时候就会发现,大部分的问题其实都是由几个不起眼的小问题累积而成的。在问题分析的过程中,往往需要用到很多与非开发技能相关的知识,比如操作系统、计算机网络、数据库,甚至硬件相关的知识。所以我一直认为,判断一个程序员牛不牛逼,还是要看他解决问题的能力!
