目录
业务背景
涉及过程
操作步骤
尝试MSCK REPAIR TABLE
尝试REFRESH TABLE
REFRESH TABLE和MSCK REPAIR TABLE区别
验证
报错日志
结论与建议
业务背景
在ETL接入数据时,需要对表新增字段,因为表的特殊性质,存在实时接入更新三个月历史数据的情况,故该表的小文件很多,在通过hive增加字段的时候,spark没有立即生效,导致用hive命令修改元数据后, 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 执行比直接spark.sql速度快,通过spark shell 执行用时20分钟,通过spark.sql用时50分钟
--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
使用spark-sql,对表执行refresh table table name操作也是执行成功了,同时再次启动ETL任务还是会加载文件
开始考虑增加spark Streaming的资源,增加driver的参数,看是否可以执行执行过去,尝试过后发现还是失败
后面考虑手动修改hive元数据中spark的schema缓存属性,考虑到改元数据风险太大,可能导致hive整体崩盘,不建议,就没有操作
其语法如下:
: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, ...
第四种,考虑如果后面还不成功尝试生成新表,后面把历史的数据同步到新表里面,同时这种情况会影响第二天的T+1任务
考虑到之前执行refresh的时候有进行小文件合并,中间有杀掉小文件合并进程,有可能是影响了refresh,故再进行了小文件合并后又重新执行了refresh,才成功了,且最后一个是通过spark shell执行的
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.
结论与建议
结论:
- 元数据不一致问题:在你的ETL过程中,由于Spark和Hive的元数据未能同步,导致了表的元数据信息和schema不一致的问题。这可能是由于Hive在添加字段后,Spark没有立即刷新其缓存的元数据所致。
- Spark Streaming与Hive集成问题:在使用Spark Streaming更新Hive表时,由于Spark无法使用Hive存储的元数据,导致了任务失败。这可能是因为Spark Streaming在处理Hive表时,没有正确地获取到最新的元数据。
建议:
- 确保元数据同步:在进行表结构变更(如添加字段)后,确保使用REFRESH TABLE命令刷新Spark的元数据缓存。这可以通过在Spark Shell或Spark SQL中执行该命令来实现。
- 避免并发操作:在执行REFRESH TABLE命令时,确保没有其他任务正在操作同一张表,以避免潜在的冲突和错误。