一、背景
有同事反馈 Datax 从 Hive 表同步数据到 Mysql 数据翻倍了。通过查看 Datax 任务日志发现,翻倍的原因是多读取了 .hive-staging_xx 开头的文件。接下里就是有关 .hive-staging 的分析。
二、环境
Hive 版本 2.1.1
三、分析
3.1 .hive-staging_hive 产生的原因
通过 Spark SQL、Hive SQL、Hue 等提交 SELECT 或者 INSERT OVERWRITE 等 SQL 到 Hive 时,会产生该目录,用于临时存放执行结果,比如 INSERT OVERWRITE 会将结果暂存到该目录下,待任务结束,将结果复制或移动到 Hive 表中。
对应的的参数:
hive.exec.stagingdir
- Default Value: .hive-staging
- Added in: Hive 1.1.0 with HIVE-8750
Directory name that will be created inside table locations in order to support HDFS encryption. This is replaces hive.exec.scratchdir for query results with the exception of read-only tables. In all cases hive.exec.scratchdir is still used for other temporary files, such as job plans.
https://cwiki.apache.org/confluence/display/Hive/Configuration+Properties#ConfigurationProperties-QueryandDDLExecution
对应的源码:
https://github.com/apache/hive/blob/branch-2.1/ql/src/java/org/apache/hadoop/hive/ql/metadata/Hive.java
查看 moveFile() 方法
从源码可以看到,有下面几种情况
① 源文件是本地系统的文件,使用 copyFromLocalFile 代码行数: 2925~2934
② 如果是跨系统或者不同加密的数据,会使用 copy ,涉及方法 needToCopy ,代码行数:3018~3032
③ 其他情况都是 move,涉及操作 namenode 元数据,不会有额外数据操作。 (注意:这里和 Hive 1.x 不一样,在 Hive 1.x 中如果原目录是目标目录的子目录,原目录下的每个文件进行copy操作,这个效率很低的!!!,可以查看 1.x 的原码:戳我)
3.2 为什么临时文件没有自动删除?
① 任务执行失败时,这些临时文件和目录不会被自动删除掉,直到有相关的 SQL 执行成功时,才会自动删掉。
② 我们发现,在 Hue 中提交的 SQL,临时文件和目录页也不会自动被删掉。也许和长连接有关系,我尝试了多次,必现。
3.3 .hive-staging_hive 会导致的一些问题:
① 如果目标路径存在临时文件的话,datax 读取hdfs数据的时候会递归读取,所有 .hive-staging_hive 临时文件的数据也会被 datax 读到,导致数据至少翻倍。
② 有的 .hive-staging_hive 可能会包含很多的临时文件,占用空间,同时也会造成 namenode 的压力;
四、如何解决?
从 Datax 的角度分析,修改 HDFS Reader 插件,过滤点开头的文件或目录。
从集群的角度分析,修改 hive.exec.stagingdir 配置,修改成统一的目录。
hive.exec.stagingdir
/tmp/hive/.hive-staging
从用户的角度分析,不要使用 Hue 补数,使用调度系统或者 beeline 执行 SQL,这两种方式都可以保证会话(连接)断开,临时文件(目录)会自动清理。
从社区的角度分析,查看社区的 issue ,有其他用户遇到了这个问题: Hive is not cleaning up staging directories 也可以看出,除了上述分析的原因,也可能有一些奇奇怪怪的bug导致临时文件不会被清理。
看到两个修复:
① https://issues.apache.org/jira/browse/HIVE-17479 3.0 版本
When these queries are internally rewritten, a new context is created with a new execution id. This id is used to create the scratch directories. However, only the original context is cleared, and thus the directories created with the original execution id.
The solution is to pass the execution id to the new context when the queries are internally rewritten.
② https://issues.apache.org/jira/browse/HIVE-20409 4.0版本
五、总结
hive-staging文件不会自动删除,有些未知的情况还无法避免。
- 会浪费存储
- 会影响datax同步数据,datax hdfs reader 也会把临时目录的数据同步到下游。
我认为最优的解决方案是,临时文件改成统一的目录,这样即使有临时文件没有自动删除,我们也可以进行周期性的监控并清理没有及时清理的过期的临时文件。
hive.exec.stagingdir
/tmp/hive/.hive-staging
另一种方案,不要使用hue刷数据,使用调度或beeline执行SQL,大概率(不排除是不是有其他bug)不会出现临时文件不会自动清理的情况。
大数据学习指南 专注于大数据技术分享与交流。