Spark 2.1.0与Hive 2.1.1在MapR集群中表架构不同步问题求助
解决Spark 2.1.0与Hive 2.1.1(MapR集群)中表架构不同步问题
我之前在MapR集群里也碰到过一模一样的问题,当时折腾了好一阵子才摸清楚根源和解决办法。先给你拆解下问题出在哪,再一步步说怎么解决:
为什么会出现架构不同步?
- 当你用
saveAsTable创建托管/外部表时,Spark会同时在Hive元数据中注册表的完整架构,并且把数据写到对应的存储路径(托管表用Hive默认路径,外部表是你指定的路径)。 - 但如果直接用
mode("overwrite").parquet("path/to/table")去覆盖底层Parquet数据,这个操作只会修改存储里的文件,完全不会碰Hive元数据。要是新的Parquet数据架构和原表不一样,自然就会出现元数据和实际数据架构不匹配的情况——不管是托管表还是外部表,只要绕开了Spark的Catalog API操作底层存储,都会触发这个问题。 - 另外,Spark 2.1.0本身在Hive元数据同步这块有局限性,不像新版本那样能自动感知底层数据变化,所以手动操作存储后很容易出问题。
具体解决方案
方案一:优先用Spark Catalog API操作表(最推荐)
这是从根源上避免问题的方式,确保元数据和数据始终同步:
- 如果要覆盖数据甚至更新架构,直接用
saveAsTable配合overwrite模式就行,分区表的话可以加个动态覆盖的参数,避免全表重写:df.write .mode("overwrite") .option("spark.sql.sources.partitionOverwriteMode", "dynamic") // 分区表可选,只覆盖目标分区 .saveAsTable("your_db.your_table") - 这样操作会自动更新Hive元数据里的架构,同时覆盖对应的数据文件,完美保证一致性。
方案二:手动刷新元数据(如果必须写底层路径)
要是因为业务限制必须直接写Parquet路径,那写完之后一定要手动刷新元数据:
- 在Spark里执行刷新表命令:
或者用Scala代码调用:REFRESH TABLE your_db.your_table;spark.catalog.refreshTable("your_db.your_table") - 如果是外部表,还可以用Hive的MSCK命令修复表,同步分区和架构信息,Spark 2.1.0里可以通过Spark SQL执行:
spark.sql("MSCK REPAIR TABLE your_db.your_table")
方案三:调整Spark配置增强自动校验
Spark 2.1.0有个配置可以让Spark读取表时自动检查底层数据的架构,虽然会增加一点性能开销,但能避免用过时的元数据:
- 在你的Spark作业里添加这个配置:
spark.conf.set("spark.sql.hive.verifyPartitionPath", true)
MapR集群额外注意点
- MapR-FS有自己的缓存机制,写完数据后最好等个几秒钟再刷新元数据,确保文件系统的元数据也同步完成了。
- 托管表尽量别直接碰它的底层存储路径,毕竟托管表的生命周期是由Catalog管理的,手动改存储很容易搞出数据丢失或者元数据混乱的问题。
内容的提问来源于stack exchange,提问作者hulin003
相关产品推荐
相关产品推荐

