如何对Unix服务器上两个含10亿条记录的文件进行高效比对
10亿级Unix服务器文件比对Java实现优化方案
优先选用Unix原生工具(性能最优)
Unix自带的文本处理工具基于外排序实现,天然支持大文件处理,无需担心内存溢出问题,性能比自行实现的Java代码高1到2个数量级:
- 先对两个文件做排序,sort工具会自动利用磁盘缓存处理超大数据,不会占用过多内存:
sort file1 > file1_sorted sort file2 > file2_sorted - 直接用comm工具完成比对:
# 输出结果第一列为仅file1存在的行,第二列为仅file2存在的行,-3参数隐藏两个文件共有的行 comm -3 file1_sorted file2_sorted
如果业务要求必须用Java实现,可参考以下优化方案:
Java实现核心优化
内存优化(解决OOM问题)
绝对不要全量读取文件内容到内存,10亿条记录即便单条仅占10字节,总容量也达到10GB,远超过常规JVM堆内存上限,采用分片+外排序方案处理:
- 分批次读取第一个文件,单批次读取量根据JVM堆内存调整,控制在1GB以内(约100万~500万行),按行内容哈希值取模写入对应临时分片文件(例如分1024个分片,相同内容的行一定会落入同一分片)
- 采用相同分片规则处理第二个文件,生成相同数量的临时分片
- 逐一对相同编号的分片做比对,单个分片大小可完全载入内存处理,不会出现内存溢出
- 读取文件使用
BufferedReader或NIOFileChannel流式读取,禁止使用Files.readAllLines等全量读取API,每行处理完成后立即销毁引用,加快GC回收
性能优化
- 调整文件读取缓冲区大小,
BufferedReader默认缓冲区为8KB,建议调整到64KB~1MB,减少IO交互次数:BufferedReader br = new BufferedReader(new FileReader("/path/to/file"), 1024 * 1024); - 若文件行格式固定,优先使用字节流读取,跳过字符编解码环节,可提升30%以上读取性能
- 分片比对时仅需判断行是否存在,采用
HashSet存储单分片内容,查询时间复杂度O(1);需要统计出现次数则采用HashMap计数 - 分片之间无数据依赖,可开启多线程并行比对,线程数设置为CPU核心数*2即可,充分利用多核性能
额外优化建议
- 比对前先计算两个文件的MD5值,若MD5完全一致可直接判定文件内容相同,无需逐行比对
- 若允许去重,分片写入前可先对单批次内容做去重处理,减少后续比对计算量
- 所有临时分片文件处理完成后主动删除,避免占用磁盘空间
内容的提问来源于stack exchange,提问作者Dinesh
相关产品推荐
相关产品推荐

