作者:杨考 微信 : devin_cn_hd_09_16 欢迎讨论问题
在每次收到阅读者添加微信并开始交流讨论,心理是无比的激动。
一、日志系统的需求和设计目标
最基本的需求【下图黑色部分所示】 : 完成日志写入文件,保证无丢失,不影响正常业务,检测写入异常
关注的性能、和衍生需求【下图绿色部分所示】 : 日志的可读性、写入性能、并发写入控制等
终极目标【下图黄色部分所示】 : 简洁、完整、可读性好的日志
二、日志等级分类【略过】
一般都是如下几种,甚至可以扩充,这里不做详述
DEBUG
INFO
NOTICE
WARNING
ERROR
FATAL
三、日志系统的设计
1.设计方案
2.方案对比
方案1 | 方案2 | 方案3 | 方案4 | |
写入性能 | 非常差 不适合生产环境 | 性能好 有并发写入问题 | 性能好 并发写入可控 | 性能好 |
日志延时 | 无 | 无 | 基本无延时 | 有一定延时 |
降级预案 | 删除写入锁 或控制输出量 | 不变 或控制输出量 | 不变 或控制输出量 | 不变、切断第三方 或控制输出量 |
3.性能测试
这里公布调研结果
1.文件写入+加锁,单机单进程测试意义不大,一般都是并发串行化,导致写入时间长
关于 open+write、 fwrite、file_put_content的性能就不再这里赘述了。
同样单机单核测试 (APPENDEX | LOCKEX) 和 (APPENDEX ) 的性能价值不大
2.追加写入的性能绝对没问题。
3. 增加一级内存缓存,写入频次变低,对于写入的性能有一定的提升,并且可以支撑一定量的频繁写入。
4. 为了加速日志的处理过程,增加一级第三方中间件,用来存储部分存储日志,而非全量数据,问题排查还是需要通过日志文件完成,第三方只能减少日志分析的相关数据的延时时间。
4. 方案总结
基本选择的是方案3作为一个终极日志系统的设计方案。
四、数据瓶颈
有了日志系统,使用者应该根据业务特点、日志量、延时需求等将日志严格分级。
如果分级后的日志数据量还是很大,需要对日志分级再进行分类。
如果分级后的日志写入,并发写入导致日志的脏数据比例很高,则建议按照进程或者线程ID做hash或者隔离,再次细分日志文件。
五、常见问题
1. 日志文件不做切分
日志文件过大,写入速度慢,甚至占用磁盘空间过大
2. 磁盘空间监控
磁盘满,则写入日志错误,同样业务也出错。需要监控
3. 限制一次写入日志文件的大小
对于文件系统来讲,没有严格写入文件数据大小的限制,但是单行日志过大,写入速度慢,同时给下游分析程序也带来了一定的内存困扰。
建议使用者控制每行日志数据的大小
不建议在日志系统层次限制单行日志数据的大小
4. 并发写入【写入日志文件不加锁】
一般的服务端程序,很少能触发日志的并发写入
即使有日志的并发写入,如果没有一定监控机制,很难发现日志写入错误
当业务量达到一定程度,而且需要关心业务数据时,业务方或者日志下游需要严格校验日志数据。业务方要针对并发写入点进行优化。
六、实践发现问题
1. 日志处理流程
如上图示,日志处理环节发现日志格式错误,日志数据错误
2.日志系统按照方案2的方式进行设计
日志并发写入很正常,无法避免,但是有20%多的有效日志都是因为并发写入,变成了赞数据,不得不丢弃。这个无法忍受
3.并发日志问题的解决
发现并发写入日志有2大规律,
第一:写入16K的时候,自动被截断的占15%以上。如下图示,进行日志截断和拆分,将日志单条日志大小控制在16k以内,并发写入脏数据得到了控制
大于16K的日志就写不进去了吗?并非如此,大于16K的日志是可以完整的写入日志系统,这里初步预估,文件系统底层应该是按照内存页进行写入,预估16K应该是一个页,在16K写入之后,后面的写入部分被其它并发写入的日志冲掉了。
第二:照样还有一部分,并非超过16k导致的,
有另外一个日志打印也很频繁,将这个频繁的日志,从这个日志文件拆分出去
至此:仍然有并发写入的问题,只是错误日志的行数已经很少,可以忽略不计了。
4.规划使用方案4,只采集需要分析的日志到写入性能高的第三方中间件【MQ、kafka】中
因为要保证有效日志的准确性,且不丢失,后续将使用方案4,将专需日志统一入第三方中间件,这样就可以避免其它日志并发写入导致这里的日志错误。