国庆节后,系统部同事说节日期间k8s集群被事件日志写满,为了不影响期间正常使用对其中的一些数据进行手动删除。经排查是事件日志未被正常删除所致,希望我们配合排查。
为保证大数据日志采集的可靠性,在日志采集过程中会将日志以分钟文件的形式写入服务器磁盘指定目录,并定期归档和删除。当数据处理下游集群出现异常导致原始数据丢失时可以通过服务器本地磁盘的数据进行数据恢复。
这次出问题的机器是部署在k8s集群中的服务。首先,排查的就是定期归档和删除的脚本是否正常执行。
该脚本在服务器中通过crontab每秒执行一次,其包含两个功能:归档和删除。删除功能是每天凌晨4点整执行一次。
通过观察发现归档功能正常,说明脚本在pod中是能够执行的。
而脚本的归档和删除功能在单体应用中可以被正确执行。
那么,问题就变为在k8s集群和单体应用在删除功能上有何不同。
与相关同事在梳理中发现自己对于该脚本在k8s集群中的运行方式有些想当然。我以为所有pod都是将日志写入到服务器本地磁盘,并且脚本也是在物理机上执行。然而,现实是日志直接写在pod里,这样pod中的数据还有丢失风险。删除脚本也是在pod里执行。
在一台物理机上运行多个pod实例,比如20个吧。那么,脚本每秒会执行20次。
这时和同事沟通将pod中指定目录挂载到物理机上,这样排除日志丢失的风险也能保证数据能正常删除,手动运行脚本结果也正常。
但是,第二天发现有部分机器能正常删除成功,而有部分机器不能正常删除成功。这个结果让我百思不得其解。但至少说明修改是有效的。
在与同事沟通中提到其只是修改k8s配置,并未对原有的pod进行重启。也就是说有一部分pod的数据还是写在pod里。并在阅读删除脚本时发现两个细节:其一,脚本上使用文件锁,意味着每次脚本任务执行只能有一个进程拿到锁并成功执行。其二,每次拿到锁之后会sleep 10s。
然后,恍然大悟。在k8s集群的某台服务器上运行20个实例,其中有2个实例是将数据挂载到物理机上。在凌晨4点,脚本执行,因为锁和延时的存在,一分钟内最多只能执行6次。若刚好有2个实例中的一个执行到,那么物理磁盘上的数据会被清除,否则数据将会被保留。
最后,决定将脚本执行的crontab调度拿到物理机上执行,且将所有的pod重启并将指定目录挂载到物理机中。
问题解决。
回顾整个解决问题的过程,问题出现的原因是环境变化导致原本可用的任务变的不可用。这个在编程中要非常注意,当下你写的代码包含很多你认为理所当然的假设,而其并非真的理所当然。 问题的出现是你想象的真实和现实不符所致。问题解决的过程就是不断拉齐两者的过程,去探索“真”。
如道家的“修真”。