目录
REFRESH TABLE和MSCK REPAIR TABLE区别
业务背景
在 ETL 过程中,向表中新增字段时,由于表的特殊性质,存在实时接入和更新三个月历史数据的情况,导致小文件过多。使用 Hive 增加字段时,Spark 的 schema 没有立即生效,这会造成 Hive 表的元数据与 Spark SQL 的 schema 不一致。需要通过 REFRESH TABLE
命令刷新表,同时要求没有其他任务同时操作该表(包括插入和读取),以确保数据一致性。
当使用 Spark Streaming 更新 Hive 表时,可能会出现以下问题:
- 警告信息:
WARN HiveExternalCatalog:The table schema given by Hive metastore...
,表明 Spark 无法使用 Hive 存储的元数据,需要从所有分区表中读取元数据信息。 - Spark 任务卡在
Listing leaf files
阶段,尽管只对部分分区进行了更新,但Listing
过程却扫描了所有分区(如 500 个分区)。
涉及过程
操作步骤:
- 修改 MySQL 配置:在 ETL 字段中进行更改,同时通过 Hive 命令增加字段。
alter table table add columns (***) cascade;
- 执行刷新操作:使用 Spark Shell 执行
REFRESH TABLE
命令,相比直接使用 Spark SQL,Spark Shell 执行速度更快。示例命令:
--history |grep spark-shell24
spark-shell24 --conf spark.dynamicAllocation.maxExecutors=100 --conf spark.dynamicAllocation.minExecutors=10 --executor-memory 25g --executor-cores 5 --conf spark.sql.shuffle.partitions=2000 --driver-memory 16g --queue root.yarn_etl.etl --conf spark.driver.maxResultSize=5g
spark.sql("REFRESH TABLE table")
尝试MSCK REPAIR TABLE
尝试使用MSCK REPAIR TABLE修复表,执行成功,同时对结果未有影响
尝试REFRESH TABLE
尝试其他命令:
- MSCK REPAIR TABLE:修复表结构,无明显效果。
- 手动修改 Hive 元数据:考虑修改 Hive 元数据中的 Spark schema 缓存属性,但因风险较大,未进行操作。
- 生成新表:如果无法解决,考虑生成新表并同步历史数据,但会影响后续的 ETL 任务。
其语法如下:
:Set Table Properties:添加或修改TBLPROPERTIES
ALTER TABLE table identifier SET TBLPROPERTIES(key1=val1,key2 =val2,...)
--Unset Table Properties:删除TBLPROPERTIES
ALTER TABLE table identifier UNSET TBLPROPERTIES [ IF EXISTS ]( key1, key2, ...
REFRESH TABLE
和MSCK REPAIR TABLE
区别
在Spark中,
REFRESH TABLE
和MSCK REPAIR TABLE
都与元数据管理和表分区有关,但它们有不同的作用和用法。
REFRESH TABLE
:
REFRESH TABLE
命令用于刷新表的元数据。当表的元数据发生变化(比如添加、删除、修改分区),但这些变化没有被及时反映到Spark的元数据缓存中时,你可以使用REFRESH TABLE
命令来强制Spark重新加载这些元数据,以确保Spark中的元数据与数据存储中的实际情况保持一致。这个命令通常用于当你手动添加或删除了表的分区时,为了让Spark能够识别到这些变化,你需要执行
REFRESH TABLE
。
MSCK REPAIR TABLE
:
MSCK REPAIR TABLE
命令用于修复表的分区,特别是针对外部表(external tables)。当你有一个外部表,数据被添加到了表的分区目录中,但是表的元数据没有被相应地更新,这时你可以运行
MSCK REPAIR TABLE
命令来检测分区目录中的数据,并更新表的元数据,以便Spark能够识别到这些分区。这个命令通常用于处理外部表的分区,因为外部表的分区通常不是由Spark管理的,而是由外部数据源(如Hive、HDFS)管理的。因此,使用
MSCK REPAIR TABLE
可以确保Spark中的元数据与外部数据源中的实际情况保持一致。总的来说,
REFRESH TABLE
用于刷新表的元数据,而MSCK REPAIR TABLE
用于修复外部表的分区。在使用时需要根据具体的情况选择合适的命令。
验证
--查询desc formatted 表名 partition(day=20240301);看要加的字段加上去没有
desc formatted sdk_public.mobpush_event_detail partition(day=20240301);
--查询表字段
desc 表名
问题点:通过上面的命令不管是表还是分区,字段都是加上的,同时后面执行还是会走的Listing leaf files这一步
报错日志
24/03/05 20:20:33 WARN org.apache.spark.internal.Logging: The table schema given by Hive metastore(struct<workid:string,rid:string,duid:string,sdkver:string,appkey:string,push_channel:string,plat:int,time:bigint,type:int,sub_type:int,factorycode:string,factorydesc:string,create_time:bigint,serdatetime:bigint,rdid:string,oiid:string,pkg:string,repeat:boolean,category:string,day:string>) is different from the schema when this table was created by Spark SQL(struct<workid:string,rid:string,duid:string,sdkver:string,appkey:string,push_channel:string,plat:int,time:bigint,type:int,sub_type:int,factorycode:string,factorydesc:string,create_time:bigint,serdatetime:bigint,rdid:string,oiid:string,pkg:string,repeat:boolean,day:string>). We have to fall back to the table schema from Hive metastore which is not case preserving.
如果在执行 REFRESH 命令的同时有其他进程正在写入文件,那么 REFRESH 命令的行为可能会受到这些写入操作的影响。具体行为取决于多个因素,包括你使用的具体系统、 REFRESH 命令的实现细节以及写入操作的性质。 1.Hive的 REFRESH 命令: 在Hive中, REFRESH 命令用于使Hive元数据与HDFS或其他存储系统同步。如果REFRESH 命令执行时,有新的文件被添加到HDFS中,那么这些新文件可能不会立即出现在Hive的元数据中,除非 REFRESH 命令能够检测到这些更改。然而,如果文件在 REFRESH 命令执行过程中被修改或删除那么这些更改可能会影响 REFRESH 命令的结果。 2.并发写入: 并发写入可能会影响 REFRESH 命令的行为。如果写入操作是在Hive表的数据目录中进行的,并且这些更改在 REFRESH 命令执行时还没有完成,那么这些更改可能不会立即反映在Hive的元数据中。 3.事务性: 如果你的系统支持事务性操作,那么 REFRESH 命令可能会等待所有并发写入操作完成后再进行元数据更新,以确保数据的一致性。 4.文件系统的特性: 底层文件系统的特性也会影响 REFRESH 命令的行为。例如,某些文件系统可能支持即时检测到新添加的文件,而其他文件系统可能需要一段时间才能检测到这些更改。 总之,如果在执行 REFRESH 命令的同时有其他进程正在写入文件,那么 REFRESH 命令的行为可能会受到影响。为了确保数据的一致性,最好在执行 REFRESH 命令之前暂停写入操作,或者在 REFRESH 命令执行后验证数据的完整性。此外,根据你所使用的系统和框架,查阅相关文档以了解 REFRESH 命令的具体行为和限制也是一个好主唐
结论与建议
结论:
-
元数据不一致问题:在你的ETL过程中,由于Spark和Hive的元数据未能同步,导致了表的元数据信息和schema不一致的问题。这可能是由于Hive在添加字段后,Spark没有立即刷新其缓存的元数据所致。
-
Spark Streaming与Hive集成问题:在使用Spark Streaming更新Hive表时,由于Spark无法使用Hive存储的元数据,导致了任务失败。这可能是因为Spark Streaming在处理Hive表时,没有正确地获取到最新的元数据。
建议
- 暂停写入操作:在执行
REFRESH TABLE
前,暂停对表的写入操作,确保数据的一致性。 - 验证刷新效果:在执行
REFRESH TABLE
后,验证表结构和字段是否正确更新。 - 小文件合并:定期进行小文件合并,减少小文件的数量,以提高操作效率。
- 监控并发写入:避免在进行元数据刷新时有其他进程同时操作该表,特别是大规模数据处理任务。
- 考虑表结构优化:如果频繁遇到此类问题,考虑优化表的结构和分区策略,减少对元数据的频繁更新。