背景
工作中有很多大数据运维治理方面的场景,比如 HDFS 小文件治理,数据生命周期管理,大文件压缩等。所以做了这个工具箱,方便使用。 项目地址:github.com/qiuyanjun88...
小文件合并设计思路
具体流程如下:
- 连接 HiveMetaStore 获取 Hive 表的元数据信息,包括:路径、存储格式、内部表还是外部表等。
- 根据 Hive 表的路径,递归扫描表底下的所有子目录,如果有多个小于256MB的文件,则标记为需要合并
- Spark 启动多线程,对有问题的目录进行合并。
核心代码实现
获取hive表元数
java
IMetaStoreClient metaStoreClient = new HiveMetaStoreClient(new HiveConf());
// 获取 hive 表对象
Table table = metaStoreClient.getTable(dbName, tableName);
// 获取表所在位置
String location = table.getSd().getLocation();
// 获取表的格式
String inputFormat = table.getSd().getInputFormat();
// 格式匹配
private String getFileFormatFromInputFormat(String inputFormat) {
if (inputFormat == null) {
logger.error("InputFormat为空");
return null;
}
inputFormat = inputFormat.toLowerCase();
if (inputFormat.contains("parquet")) {
return "parquet";
} else if (inputFormat.contains("orc")) {
return "orc";
} else if (inputFormat.contains("avro")) {
return "avro";
} else if (inputFormat.contains("text") || inputFormat.contains("textfile")) {
return "text";
} else {
logger.error("不支持的文件格式: {}", inputFormat);
return null;
}
}
获取 hdfs 目录下文件数量和目录大小
java
FileSystem fs = FileSystem.get(new Configuration());
ContentSummary summary = fs.getContentSummary(path);
// 获取目录底下的文件数量
long fileCounts = summary.getFileCount();
// 获取目录大小
long dirSzie = summary.getLength();
// 计算平均文件大小
double avgSize = dirSzie / fileCounts;
多线程启动 spark 合并
java
SparkSession spark = SparkSession.builder().enableHiveSupport().getOrCreate();
// 创建线程池
int threadCount = mergeConfig.getThreadPoolSize();
ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
logger.info("使用 {} 个线程执行合并任务", threadCount);
// 提交合并任务
List<Future<HiveTblMergeResult>> futures = new ArrayList<>();
for (HiveTblMergePath mergePath : mergePaths) {
SparkMergeExecutor executor = new SparkMergeExecutor(mergePath, config, spark, fs);
futures.add(executorService.submit(executor));
}
经过测试,SparkSession 是线程安全的,多线程同时使用不会有问题。但是需注意:同时并发处理多个任务会消耗更多资源,一般在集群业务非繁忙时段运行合并任务。
后期需要改进的地方
avro 格式文件合并
avro 文件格式有 schema,经过测试不能简单使用 spark 的 read write 进行合并,需要获取表的 schema 后才能合并,否则会出现合并后数据丢失等情况。
多线程优化,提高并发速度
代码中目前扫描还是单线程,这一点可以改进成多线程扫描。这样可以做到多线程同时扫描及合并,提高效率。