海量日志采集
在业务高峰期下,会有同时成千上万个客户端建立连接,实时上报日志数据。
在上面的高峰期场景下,日志采集服务会有不小的压力,如果程序代码逻辑处理稍有不当,就会造成服务卡顿、CPU 占用过高、内存溢出等问题。
为了解决上面的大量连接实施上报数据的场景,日志采集服务决定使用 Netty 框架进行开发。
这里直接给出日志采集程序使用 Netty 后的一些优化点,
采集日志异步化
针对客户端连接上报日志的采集流程异步化处理有三个方案,给大家介绍一下,
- 普通版:采用阻塞队列
ArrayBlockingQueue
得生产者消费者模式,对上报的日志数据进行异步批量处理,在此场景下,通过生产者将数据缓存到内存队列中,然后再消费者中批量获取内存队列的日志数据保存入库,好处是简单易用,坏处是有内存溢出风险。 - 进阶版:采用
Disruptor
队列,也是一个基于内存的高性能生产者消费者队列,消费速度对比ArrayBlockingQueue
有一个数量级以上得性能提升,附简介说明:https://www.jianshu.com/p/bad7b4b44e48。Disruptor 内存高性能消息队列_disruptor队列-CSDN博客 - 终极版:也是公司日志采集程序最后采用的方案。采用
kfaka
消息队列中间件,先持久日志上报数据,然后慢慢消费。虽然引入第三方依赖会增加系统复杂度,但是kfaka
在大数据场景表现实在是太优秀了,这一点也是值得。
采集日志压缩
对上报后的日志如果要再发送给其他服务,是需要进行压缩后再处理,这一步是为了避免消耗过多网络带宽。
在 Java 里通常是指序列化方式,Jdk 自带得序列化方式对比 Protobuf、fst、Hession 等在序列化速度和大小的表现上都没有优势,甚至可以用垃圾形容。
Java 常用的序列化框架有下面这些,
- JDK 自带的序列化:性能较差,占用空间大,无法跨语言,好处是简单易用,通用性强。
- JSON:常用的 JSON 库有 Jackson、Gson、Fastjson 等。性能较好,占用空间少,跨语言支持广泛,但是无法序列化复杂对象。
- Protocol Buffers:由 Google 开源,基于 IDL 语言定义格式,编译器生成对象访问代码。性能高效占用空间小,但是需要提前定义 Schema。
- Thrift:Facebook 开源,与 Protocol Buffers 类似。定制生态不如 PB 完善,但是支持多语言交互。
- Avro:Hadoop 生态圈序列化框架,支持数据隔离与进化,动态读写,性能可靠性好,占用空间较小。但是使用复杂,通用性较差。
- Hessian:一款开源的二进制远程通讯协议,使用简单方法提供了RMI功能,主要用于面向对象的消息通信。支持跨平台、多语言支持、使用简单,缺点是传递复杂对象性能会下降,不适合安全性高的应用。
如果兼容性要求不高可以选择 JSON,如果要求效率以及传输数据量越小越好则 PB/Thrift/Avro/Hessian 更合适。
数据落库选型
像日志这种大数据量落库,都是新增且无修改得场景建议使用 Clickhouse 进行存储,好处是相同数据量下对比 MySQL 占用存储更少,查询速度更快,坏处就是并发查询性能比较低,相比 MySQL 使用不算那么成熟。