
原文链接: https://clickhouse.com/blog/netflix-petabyte-scale-logging[1]
“在Netflix,规模决定一切。”工程师Daniel Muino的这句话,背后是一组震撼的数据:
要让这么大规模的日志“秒级可查”,光靠ClickHouse还不够。Netflix团队靠3个关键优化,才实现了“日志生成20秒内可搜、部分场景最低2秒延迟”的体验(远优于5分钟SLA)。
Netflix的日志流程并不复杂,但每一步都经过取舍:

source:https://clickhouse.com/blog/netflix-petabyte-scale-logging
最终效果 点击日志事件、展开JSON payload、按指纹哈希分组百万条消息,都不用等查询“转圈”。
日志要有用,首先得“去重归组”(即指纹识别):把百万条相似日志(如仅ID不同)压缩成一个模式,避免工程师被噪音淹没。
Netflix团队踩过两个坑:
最后他们换了个思路:“日志识别和编译器分词是同一个问题,解法也一样——用词法分析器(lexer)”。 团队用JFlex(Java工具)生成优化后的词法分析器,把日志模式编译成高效代码,而非 runtime 解析复杂正则。 效果立竿见影:
指纹识别后,日志要以“每秒百万条”的速度写入ClickHouse,这一步又遇到了序列化瓶颈。
最初方案是JDBC批量插入:简单但低效——每次预编译语句都要协商 schema 和序列化细节, overhead 随规模暴涨。
团队先降到更低抽象层:用ClickHouse Java客户端的RowBinary格式,手动逐列序列化(如把DateTime64编码成“从 epoch 开始的纳秒数”),虽获性能提升,但仍不满足。
epoch 指的是“记时的零点”。最常见的是 Unix epoch: 1970-01-01 00:00:00(UTC)。
真正的突破来自一篇ClickHouse博客:原生协议(native protocol)的性能远超RowBinary[2],但Java客户端不支持(仅Go客户端支持)。 于是Daniel直接逆向工程Go客户端,自己造了个编码器:用原生协议生成LZ4压缩块,直接写入ClickHouse。 最终效果:CPU占用更低、内存效率更高,吞吐持平甚至超过RowBinary——“虽未完美,但还有很大优化空间”。
日志查询中,工程师严重依赖“自定义标签”(如按微服务名、请求ID过滤),但标签也成了查询性能的“重灾区”。
原来的存储方式是Map(String, String):ClickHouse会把Map存成“键数组+值数组”,每次查询都要线性扫描——而Netflix每小时有2.5万个唯一标签键、数千万个唯一值,扫描速度极慢。
团队先试了ClickHouse创始人Alexei建议的LowCardinality类型:对标签键有效,但标签值太多,无法覆盖。
最终解法很简单:给Map分片。把标签键哈希到31个小Map里,查询时直接定位到目标分片,不用全量扫描。
效果惊人:
这三个优化没有复杂技巧,本质都是“简化”:
正如Daniel所说:“成功的关键不是耍小聪明,而是通过简化,让系统做最少的无用功。”
对Netflix而言,这套系统不仅是“日志存储”——更是支撑3亿用户流畅观影的“故障排查生命线”:从“等查询”到“秒级响应”,背后是每一个优化细节的积累。
[1]https://clickhouse.com/blog/netflix-petabyte-scale-logging
[2]原生协议(native protocol)的性能远超RowBinary: https://clickhouse.com/blog/clickhouse-input-format-matchup-which-is-fastest-most-efficient