写之前这里先打个广告,java 版本的logstash已经开源,git地址 https://github.com/dtstack ;再放个招聘信息 https://m.zhipin.com/weijd/v2/job/de2292afc38d32fe1XV73t25EFU~?date8=20180609&sid=self_jd&from=singlemessage&isappinstalled=0,欢迎对技术有追求的码农。
下面进入正题。
一是提升性能:
先说说性能问题,当时袋鼠云的云日志系统日志接收端是ruby 版本的logstash,存储用elasticsearch,前端的展示没有用原生的kibana,而是自己写的一套前端。本人是负者日志接收端的logstash开发,基于ruby版本的logstash写一些满足公司业务的插件,当时为了提升性能做了各种优
化,一些模块也用java写的,在用ruby调用java,比如ip的解析,但是最终优化的结果是单机4core,4g的虚拟机每小时最多跑800万的数据(我们的场景跟大部分人一样都是订阅kafka的消息,在经过一些filter(瓶颈主要在这里比较耗cpu),在写入elasticsearch)。因为logstash的核心代码是用ruby语言开发,虽然是运行在jruby上,但是由于中间涉及到数据结构的转化,性能是跟用原生的
java语言运行在jvm上肯定是有所差距的。所以当时也是抱着试试的心态,花了2个星期用java重写logstash,并把自己所需要的插件也用java重写,在同样的4core,4g的虚拟机环境下,每小时能跑4000万数据,性能近5倍的提升。
这是一个java logstash 和 ruby logstash(2.3.2版本)做的性能对比
二是保证数据尽量不丢失:
ruby 版本的logstash 对保证数据不丢失这块没做太多的设计,举个简单的列子,数据从kafka消费,在output到elasticsearch,一旦elasticsearch集群不可能,ruby logstash会重试几次还不成功就会扔掉继续消费kafka数据,而且重试的动作也是elasticsearch插件自身完成,logstash本生没对数据的不丢失做设计。而java 版本的logstash 的BaseOutput 这个抽象类里面有个failedMsgQueue 这个队列,每个output实例维护一个,output 插件需要自身判断哪些数据失败了,在把失败的数据调用addFailedMsg 这个方法,写入到failedMsgQueue这个队列里,java logstash一旦发现failedMsgQueue有数据就会调用sendFailedMsg这个方法消费failedMsgQueue这里的数据直到没有数据,才会消费input里的数据这个逻辑可以通过consistency 这个属性控制,默认是关闭的。还有一点是input和output插件都提供了release方法,这个主要是为了jvm退出时,要执行的一些动作而设计的,因为大部分的input和output插件在获取和发送的数据都会先放在一个集合里面,在会慢慢消耗集合里面的数据,这样jvm退出时,插件各自就可以实现自己的逻辑保证jvm退出时,集合里面的数据要消费完,才能退出jvm,当然 你要是kill -9 进程那就没法保证了。现在elasticsearch插件我们已经实现了数据不丢失这个逻辑,也在我们的线上稳定的跑了很长一段时间。
注释:有人问jlogstash跟hangout有什么区别,这里就不做说明了,有兴趣的同学可以看看这两个的源码就知道区别了。也希望jlogstash能为一些开发者解决一些问题,也希望有更多的人参与到jlogstash的开发里来。