关于性能优化
最近两周一直在对去年开发的logwatch进行重构和升级,修复一些小bug、
扩展了对文件名的正则支持、升级了相关的三方依赖库,重新规划了目录结构,
当然,优化性能也是很重要的一个目标。
越来越难的性能优化
去年开发logwatch替换logstash的时候,就是因为logstash的性能差。
所以着重在优化logwatch的性能上,上线的版本可以达到每秒5万行NginxLog。
当时主要的优化手段是提高正则解析的效率,以最低的回溯代价完成解析。
而后在一些关键数据结构上做到重用,大大降低了table的性能开销。
最后有针对性的优化了KafkaClient的参数,保证高效率的消息传递。
这次再要优化性能已经非常困难了,从profiler的统计看,热点已经不在Lua了。
所以优化的方向主要是提升依赖的三方库的性能,优化的目标是7万以上。
三方依赖
最吃cpu的三方库就是cjson,花了点时间寻找性能更好的json库。
参考了网上的一些测试结果,和自己的简单测试,发现rapidjson是最快的。
rapidjson相关的资料在网上可以搜到,大概比cjson快了一倍多。
因为lua本身提供的基础库非常有限,甚至连Sleep这样的功能都没有原生提供。
这次升级和优化时,也将一些通过os.exec来执行的命令替换成相关的三方库。
比如,引入了LuaFileSystem来丰富对目录和文件的操作,通过ffi来实现sleep。
虽然这些改进不能明显的提高性能,但是可以降低吞吐量的波动性。
在数据压缩方面由snappy换成了lz4,测试结果表明lz4还是会更快一些。
修改kafka的参数socket.blocking.max.ms也可以提高一些性能,测试结果显示
80-100之间是最佳状态。
关于Lua的Ipairs和Pairs网上有很多介绍的资料了,性能上ipairs肯定是更好的,
但是pairs的操作更方便,代码更整洁。所以要根据情况来取舍。
高密度执行的语句中,尽量使用ipairs,反之可以用pairs。
经过一番折腾,可以在理想环境(haswell或者broadwell的cpu、网络延迟低)下,
达到每秒8万以上的吞吐量,一般情况也可以超过7万。
是否过度优化
跟朋友讨论时也谈到logwatch是不是过度优化了性能,应该去实现更多的功能,
很少有业务能把日志打印量做到每秒几万行,这样的性能几乎无用武之地。
这里谈一下我的看法:
性能测试都会基于一定的前提或者一定的测试数据,多少会有一些局限性。
我的测试数据是来自生产环境上的nginxlog,每行均长是200字节。
这个测试数据的标准不算很高,我问过几家公司的朋友他们的均长在300左右。
因为业务的差别和logformat的差异,每家都会不太一样。
当然即使是300的均长,logwatch的吞吐能力也在6W以上,足够满足需求。
日志采集的探针是一个小组件,每个人都希望他是低负担的,低成本的。
如果性能做的好,在部署上就不会带来任何负担。比如,不用单独为它准备
一个cpucore,或者扩充系统内存之类的。logwatch在生产环境下,
每秒处理500行log,占用24m内存,单核的百分之1.5的cpu。
不一定每个使用它的场景都会有那么好的cpu和网络,这些不确定性也会导致
性能有所下降,提升性能会让它适应能力更强。
网上看过很多日志采集的方案,最近一年多比较流行的方案是在本地只做基本的
行和多行切分,其他的解析操作全部扔到后面去做,比如Kafka的Consumer。
这当然是一个不错的方案,但是将如此重Cpu的工作全部放在后端处理,意味着
你需要一个比较大的资源池,也会有一些相应的管理成本。
在我看来适当的将日志解析的工作放在前端agent执行,是更经济的做法。
最后
任何一种选型或者方案都不会是完美的,要看你对哪一方面更敏感,
明确知道这个方案的边界,尽量避免触礁,被滥用是很多项目失败的根本原因。