上个月就想总结写一篇关于日志切割的文章,后来跟进了一篇python logging RotatingFileHandler的日志切割实现,今天再补充一个linux logrotate的实现原理。 有兴趣看logging RotatingFileHandler的文章,附带连接 http://xiaorui.cc/?p=3114

    别问我 logrotate 是啥?  一边去 !   logrotate 是个功能强大的日志切割服务,可以根据自定义的时间及文件大小进行切割打包日志。 并且logrotate也可以做一些收尾的动作。    我想关于logrotate的用法大家都很熟悉,但你们有没有关注过他的实现方法? logrotate怎么做到日志切割的情况下还不影响业务。


该文章写的有些乱,欢迎来喷 ! 另外文章后续不断更新中,请到原文地址查看更新。http://xiaorui.cc/?p=3275

简单看了下logrotate的源码,虽然logrotate.c有2500行,对于我们来说只关心logrotate是如何切割日志的.  下面copyTruncate函数其实就两个动作,一个是copy源日志到新的日志文件里,然后清空源日志文件。

这是logrotate的源码地址, https://github.com/logrotate/logrotate/blob/master/logrotate.c 

下面是我用python写的测试代码,逻辑很简单就是写日志, 不停的让日志变大变膨胀. 

首先我们要知道在linux下所有的文件都有inode号,一个inode号也只能对应一个文件。 

第一种方法,学名 CopyTruncate:

当我们运行程序不停的写入日志,在我运行logrotate切割日志后,我们通过lsof查看进程的文件描述符,发现debug.log inode还是一个,没有被换掉。

那么他是如何切割的日志,难道是复制过去的?   你说的对!  他还真是copy复制的方式实现的日志切割,copy完成之后,会清空debug.log文件。  对于程序来说是无感知的,照样写入。   

会丢失数据么? 
会的,本来日志有100w行,程序的日志还在不停的写入,当我copy并别名后,再去清空源日志的时候,源日志很有可能现在是100w+了。 后面你懂得….

为什么要copy复制日志文件,而不是mv ?
copy / mv没有改变源文件的信息以及 inode 属性

第二种方法, 方法叫  send signal :


上面的方法保证了文件的inode不变化,这样我们的程序不需要有任何的变动。 其实logrotate还有比较优美的方法,  简单说send signal的实现原理是让logrotate给日志生产者发送重载信号。 在继续详细描述logrotate send signal之前,我们先看看nginx是如何处理日志切割的问题。


nginx master处理了signal USR1信号,当nginx收到这信号后会重新创建日志对象,确保日志往新的access.log写入。 

logrotate跟nginx的实现思路是一样的,但logrotate只是个日志消费者,而不是生产者,所以他做了跟上面逻辑一样的事情,针对日志做别名,然后给日志的消费者发送特定信号。  logrotate可以自定义脚本来发送信号。

postrotate指令可以自定义命令,另外如果你的服务端压根不支持日志的重载,那么你发了信号也是徒劳的。 

在github和stackoverflow搜到了关于Logrotate lost data的话题。 跟我的想法一样,这些老外也认为反正都是日志,丢就丢吧.   一般日志切割的crontab周期是半夜三更,这时候访问本来就不多,可以说足够规避丢日志的情况.   如果你的日志写入一直都是那么着急忙慌的,又不想丢失日志,可以用第二种的方法。 



对Python及运维开发感兴趣的朋友可以加QQ群 : 478476595 !!!

另外如果大家觉得文章对你有些作用!   帮忙点击广告. 一来能刺激我写博客的欲望,二来好维护云主机的费用.
如果想赏钱,可以用微信扫描下面的二维码. 另外再次标注博客原地址  xiaorui.cc  ……   感谢!
暂无相关产品