Skip to content
本站总访问量次, 访客数人次

The One Billion Row Challenge(1BRC): Java 处理亿级别数据的性能调优

跟大家分享一个十分有意思的比赛 —— The One Billion Row Challenge 简称 1BRC。

比赛介绍

它是由 Gunnar Morling 发起的一项挑战:给定计算任务,探索其在只使用 modern Java 的要求下能达到的最佳性能。 比赛的要求只能使用纯 Java 技术,不能使用 JNI、不能使用其他 JVM-based 语言。

通过这项比赛,可以学习到 modern Java 的各种优化技术,比如

  • (虚拟)线程
  • Vector API 和 SIMD
  • GC优化
  • 利用 AOT 编译
  • 等各种其他"奇技淫巧"

Gunnar Morling 是一位十分资深的 Java 程序员,他在 Twitter 上有 48.9 k follower.

计算任务:给定一个 csv 文本文件,每一行包括一个键值对,键是 string 类型,值是 double 类型;要求对这一亿行数据做聚合(group by)操作,算出每个分组的 min、mean、max。

本文后半部分是自己想到的优化思路。

另外,再提前挖两个坑,有时间再填 :)

  • 学习一下前几名提交的代码,看能否学到一些不知道的优化技巧。
  • 比赛讨论区还有很多人提交了非 java 的实现,可能也蛮有意思,比如 duckdb 等

原理层面的思考🤔

一个程序执行时分为哪几个阶段呢?主要是三个阶段:

  • I/O: 包括读、写两个过程,可能的形式包括 文件读写、网络读写
  • CPU 计算
  • 缓存:中间结果存在 memory 或者 cache 中

要提高性能的话,每个阶段宏观的优化思想(包括但不限于):

  • I/O: 减少阻塞
  • CPU 计算:提高利用率(尽可能打满 CPU),提高有效计算的利用率(减少浪费)
  • 缓存:高效的缓存策略,减少 I/O 开销,尽可能使用更高级的缓存(L1 cache > L2 cache > ... > Lx cache > RAM memory > 持久化内存PMEM(Persistent Memory) > SSD > HDD)

具体优化技术

个人看法,具体的优化技术主要可以从如下几个方面思考

  • 由聚合操作,想到可以借鉴数据库中的优化技术
  • JVM 语言相关的优化
  • 系统层面的优化
  • 数据结构的高效使用

数据库优化

优化简介 优化原理
partition/分治法 I/O,CPU: 并行读取、计算,降低 IO开销、提升 CPU 利用率
batch processing/批处理 I/O,CPU,缓存: 相比于 tuple-at-a-time, 有效利用系统缓存降低 IO 开销的,减少了 CPU 等IO的时间; 需要合理选择一个 batch 的大小,保证最大化 CPU 利用率的同时避免 OOM 或者 spill disk。
spill disk/溢写磁盘 缓存:考虑内存大小,针对中间结果设置写磁盘的阈值,避免 OOM

系统层面的优化

优化简介 优化原理
多线程 提升 CPU 利用率,
向量化 Vector API/SIMD 技术,提升 cache 命中率
mmap 减少用户态和内核态的切换次数,cpu 友好
写缓存 设置缓存区,大小设置为 4kb 整数倍,避免写放大

JVM 语言相关的优化

优化简介 优化原理
GC 优化 合适的 gc,减少 STW 时间,提升 CPU 利用率
AOT 编译优化 相比 jit, 占用更少内存、更快达到峰值性能
unsafe和DirectByteBuffer 直接操作堆外内存,避免不必要的 gc,提高 CPU 效率

数据结构的高效使用

优化简介 优化原理
高效的 HashTable ,使用java自带的、guava的或其他的 更少的哈希碰撞,减少 CPU 浪费;同时,避免占用过多内存

其他优化方法

优化简介 优化原理
火焰图🔥 CPU 火焰图,找到热点代码路径,针对性优化;off-cpu 火焰图,识别 I/O、网络等阻塞场景导致的性能下降;锁竞争、死锁导致的性能下降问题;内存火焰图,分析内存占用、泄露问题

Comments