InfoQ 开发者峰会慕尼黑站:如何为 1BRC 优化 Java

Java 应用在 1 亿行挑战赛(1BRC)中取得突破

2024 年 1 月,Java 应用在 1 亿行挑战赛(1BRC) 中以 1.5 秒的成绩完成了数据处理。该挑战由 Decodable 公司的软件工程师 Gunnar Morling 发起,旨在测试 Java 应用处理大规模数据的效率。在 InfoQ Dev Summit Munich 2024 上,Morling 详细介绍了参赛者如何通过优化 Java 代码实现这一成绩。

挑战背景与规则

1BRC 要求参赛者处理一个包含 10 亿行数据的文件,每行记录了一个气象站的名称和一个温度值(范围从 -99.9°C 到 +99.9°C)。参赛者需要读取整个文件,并计算 400 个气象站的最低、最高和平均温度。挑战禁止使用外部库或缓存,所有优化必须基于纯 Java 实现。

硬件与测试环境

官方测试使用的是一台 2019 年的 AMD EPYC 7502P 服务器处理器,配备 128 GB 内存。应用仅使用 8 个线程,数据文件存储在 RAM 磁盘上。尽管可用内存为 113 GB,但大多数应用使用的内存远低于此。每个提交的代码会进行五次测试,去掉最快和最慢的结果以确保一致性。

优化过程

通用优化

Morling 的基准实现耗时 290 秒。通过以下优化,运行时间缩短到 20 秒:

  1. 并行处理:在 map() 前添加 parallel() 调用,使流操作分布在 8 个 CPU 核心上,运行时间缩短到 71 秒(4 倍提升)。
  2. 并行加载:使用 Java 21 的 JEP 442(Foreign Function & Memory API)实现文件的并行加载,进一步加快数据读取。
  3. 字节级读取:将行读取从字符串改为字节级处理,结合并行化,最终实现了 14.5 倍的性能提升。

特定优化

为了将运行时间进一步缩短到 1.5 秒,参赛者采用了以下特定优化:

  1. SWAR 数据解析:使用 SIMD(单指令多数据)技术加速数据解析,SWAR 通过寄存器访问数据比主内存更快。
  2. 自定义哈希函数与映射:针对 400 个气象站的特性,优化了哈希函数和映射实现。
  3. Unsafe 类与分支预测:使用 Unsafe 类、完美值哈希、分支预测等技术进一步优化性能。
  4. GraalVM Native Image:通过 GraalVM 的 AOT 编译器生成原生可执行文件,减少 JVM 启动时间并提升运行速度。
  5. Epsilon 垃圾收集器:对于不需要垃圾回收的应用,使用 Epsilon 垃圾收集器避免不必要的资源消耗。

性能提升与最终结果

通过上述优化,1BRC 实现了从 290 秒到 1.5 秒的显著性能提升。最快的 JIT 编译器应用耗时 2.367 秒,而使用 GraalVM Native Image 的应用仅需 1.535 秒。

社区贡献与未来展望

Morling 对围绕 1BRC 迅速形成的社区表示赞赏,社区成员贡献了新的服务器、测试套件以及配置脚本。目前,Morling 尚未考虑发起新的挑战,但 1BRC 的成功展示了 Java 在高性能数据处理中的潜力。

总结

1BRC 不仅展示了 Java 在大规模数据处理中的高效性,还提供了许多适用于通用 Java 应用的优化策略。通过并行处理、字节级操作、自定义哈希函数以及 GraalVM Native Image 等技术,Java 应用在处理复杂任务时能够显著提升性能。

阅读 41
0 条评论