日志采集与传输:高性能日志采集工具、传输协议与序列化格式
做高频交易系统,日志这东西,很多人觉得不就是记个时间戳、打个字符串嘛?
我刚开始也这么想。直到有一次,系统在盘中突然卡顿,我翻日志发现——采集端把CPU吃掉了30%。嗯,从那以后,我再也不敢小看日志采集这环了。
今天咱们聊聊日志采集与传输的三个核心问题:用什么工具收日志、用什么协议传日志、用什么格式存日志。说白了,就是让日志又快又稳地从你的交易节点,流到分析中心。
核心要点:高频场景下,日志采集不能成为性能瓶颈。采集工具要轻量、传输协议要低延迟、序列化格式要紧凑。
高性能日志采集工具
市面上主流的采集工具有两个:Filebeat 和 Fluentd。我个人习惯用 Filebeat 做轻量采集,Fluentd 做复杂路由。为什么?
Filebeat:轻量级选手
Filebeat 是 Elastic 家的东西。它有多轻?我记得在某个期货公司项目里,一台 8 核机器上跑 Filebeat,CPU 占用不到 5%。
- 资源占用极低:Go 语言编写,内存常驻 20MB 左右
- 背压机制:当下游处理不过来时,Filebeat 会自动降速,不会丢数据
- 多行合并:高频交易日志经常跨多行,Filebeat 的
multiline配置能搞定
# filebeat.yml 配置示例
filebeat.inputs:
- type: log
paths:
- /var/log/hft/trade*.log
multiline:
pattern: '^\d{4}-\d{2}-\d{2}'
negate: true
match: after
output.kafka:
hosts: ["kafka1:9092", "kafka2:9092"]
topic: "hft-logs"
compression: gzip
我的经验:Filebeat 的 harvester_buffer_size 默认是 16KB。如果你日志行很长(比如包含完整订单快照),建议调到 64KB,否则会有截断风险。
Fluentd:路由大师
Fluentd 是 Ruby 写的,资源占用比 Filebeat 高一些。但它强在插件生态和路由能力。
我曾经遇到一个场景:交易日志需要同时发往 Kafka 做实时分析、发往 S3 做归档、还要过滤掉心跳日志。用 Fluentd 的 tag 和 filter 机制,几行配置就搞定了。
# fluentd.conf 配置示例
<source>
@type tail
path /var/log/hft/order*.log
tag hft.order
format json
</source>
<filter hft.order>
@type grep
<exclude>
key level
pattern ^heartbeat$
</exclude>
</filter>
<match hft.order>
@type copy
<store>
@type kafka2
brokers kafka1:9092
topic hft-orders
</store>
<store>
@type s3
s3_bucket hft-logs-archive
path logs/
</store>
</match>
避坑指南:我曾经在生产环境用 Fluentd 的 in_tail 插件,发现日志文件轮转时偶尔会漏掉最后几行。后来加了 pos_file 持久化记录读取位置,才彻底解决。记住,pos_file 一定要配!
日志传输协议
日志从采集端到服务端,走什么协议?我见过三种主流方案:TCP、UDP、Kafka。你想想看,高频交易场景下,延迟和可靠性哪个更重要?
其实两者都重要。但不同场景侧重点不同。
| 协议 | 延迟 | 可靠性 | 适用场景 |
|---|---|---|---|
| TCP | 中等(有重传机制) | 高 | 订单日志、风控日志 |
| UDP | 低(无确认) | 低(可能丢包) | 行情快照、监控指标 |
| Kafka | 低(批量+异步) | 高(持久化+副本) | 全量日志、流式处理 |
TCP:稳,但慢
TCP 有三次握手、有重传、有拥塞控制。说白了,它为了可靠牺牲了速度。我建议订单日志走 TCP,因为丢一条订单日志,复盘时可能找不到原因。
UDP:快,但会丢
UDP 无连接、无确认。行情快照用 UDP 很合适——丢了就丢了,下一帧马上来。我曾经在行情网关里用 UDP 广播日志,延迟从 2ms 降到了 0.3ms。
Kafka:兼顾速度与可靠
Kafka 是高频交易日志传输的标配。为什么?因为它把日志持久化到磁盘,还能多副本。就算消费者挂了,重启后还能从断点继续消费。
我个人习惯:所有交易日志先写到 Kafka,再由下游消费者决定怎么处理。这样采集端和消费端解耦,系统更健壮。
# Kafka 生产者配置(Java 示例)
Properties props = new Properties();
props.put("bootstrap.servers", "kafka1:9092");
props.put("acks", "all"); // 等待所有副本确认
props.put("retries", 3); // 重试次数
props.put("batch.size", 16384); // 16KB 批量发送
props.put("linger.ms", 5); // 最多等待 5ms
props.put("compression.type", "snappy");
我的建议:Kafka 的 acks=all 虽然慢一点,但能保证不丢数据。高频交易里,数据完整性比那几毫秒延迟更重要。
序列化格式
日志内容用什么格式存?JSON 还是 Protobuf?
这个问题我纠结过很久。JSON 可读性好,但体积大、解析慢。Protobuf 体积小、解析快,但调试麻烦。
JSON:简单直观
JSON 是文本格式,人类可读。开发阶段调试很方便。但它的体积比二进制格式大 3-5 倍。在高频场景下,网络带宽和解析时间都是成本。
// JSON 格式日志示例
{
"timestamp": "2024-01-15T10:30:00.123456Z",
"symbol": "BTC-USDT",
"side": "BUY",
"price": 42000.50,
"quantity": 0.1,
"order_id": "ORD-20240115-001"
}
Protobuf:紧凑高效
Protobuf 是二进制格式,体积小、解析快。我做过测试:同样的日志内容,Protobuf 比 JSON 小 60%,解析速度快 4 倍。
// Protobuf 定义文件
syntax = "proto3";
message OrderLog {
int64 timestamp = 1; // 纳秒时间戳
string symbol = 2;
enum Side { BUY = 0; SELL = 1; }
Side side = 3;
double price = 4;
double quantity = 5;
string order_id = 6;
}
我的选择:生产环境用 Protobuf,开发环境用 JSON。或者——在采集端用 Protobuf 压缩传输,到分析端再转成 JSON 方便查看。两全其美。
知识体系总览
下面这张图,是我对日志采集与传输的整体理解。你可以把它当作本章的思维导图。
总结一下:日志采集与传输,说白了就是三个选择——工具选 Filebeat 还是 Fluentd、协议选 TCP/UDP 还是 Kafka、格式选 JSON 还是 Protobuf。没有银弹,只有最适合你场景的方案。
我个人推荐:Filebeat + Kafka + Protobuf 作为高频交易日志的黄金组合。轻量、可靠、高效。你可以在自己的测试环境里跑一下,看看延迟和吞吐量的变化。