文件 I/O 优化
文件 I/O 是很多应用的核心操作。数据库、日志系统、消息队列,都离不开频繁的文件读写。优化文件 I/O,可以显著提升系统整体性能。
顺序写 vs 随机写
文件 I/O 的性能差异主要取决于读写模式:
性能差异
优化策略:
- 对于写入,尽量使用顺序追加(Append-only)
- 对于读取,尽量顺序读取,避免随机访问
- 无法避免随机访问时,考虑使用 SSD
Buffered I/O vs Direct I/O
Linux 提供两种文件 I/O 模式:
Buffered I/O(默认)
数据先写入 Page Cache,由操作系统异步刷盘:
优势:
- 利用 Page Cache,减少磁盘 I/O
- 写操作可以合并,提高效率
- 操作系统自动优化
劣势:
- 数据可能丢失(突然断电)
- 内存占用高(大文件会导致大量 Page Cache)
Direct I/O
绕过 Page Cache,直接读写磁盘:
优势:
- 绕过 Page Cache,节省内存
- 数据一致性更好控制
- 减少一次内存复制
劣势:
- 失去 Page Cache 的优化
- 需要手动管理缓存
- 对齐要求严格(缓冲区、偏移量必须对齐到扇区大小)
适用场景对比
O_DIRECT 使用详解
对齐要求
O_DIRECT 对缓冲区有严格的对齐要求:
Java 中使用 DirectByteBuffer 可以满足对齐要求:
O_DIRECT
文件 I/O 调优参数
内核参数
JVM 参数
文件系统参数
性能优化建议
批量写入
批量写入示例
MappedByteBuffer
对于需要频繁随机访问的大文件,mmap 可以提升性能:
mmap
异步 I/O
对于高并发写入,可以使用异步 I/O:
异步文件写入
本章小结
文件 I/O 优化的核心要点:
- 顺序写优于随机写:尽量使用追加模式
- Buffered I/O 是默认选择:利用 Page Cache 提升性能
- Direct I/O 适用于数据库:绕过 Page Cache,配合自己的缓存
- 批量操作减少系统调用:减少上下文切换
延伸思考
为什么消息队列(如 Kafka)选择顺序写而不是随机写?
答案在于磁盘 I/O 的特性:
- HDD:顺序写利用磁盘的预读和写合并,可以达到接近内存的速度
- SSD:顺序写和随机写差距较小,但顺序写仍然更快
Kafka 使用追加写入(Append-only log),配合顺序 I/O,在普通 HDD 上就能达到每秒百万级消息的吞吐量。这就是"用顺序对抗随机"的经典案例。