Delta Lake为什么不存在Hive覆盖写的问题

2022-07-21 13:44:26 浏览数 (1)

当你使用Spark对hive表进行Overwrite的时候,基本流程是删除metastore的表信息,删除数据,写_temp目录,移动_temp目录数据,最后写入表信息(我描述的这个流程不一定完全对,熟悉hive的大大欢迎指正)。这个过程可能很漫长,比如我们就遇到了当时spark进程正在写_temp目录数据,结果就这个时候Spark被异常杀死。当Spark进程启动后再次尝试时,就会报错:

代码语言:javascript复制
Can not create the managed table('`test`.`test`'). 
The associated location('hdfs://....') already exists.;

原因就是新进程发现还有_temp目录,以为有另外的进程正在写,所以就拒绝写了。对于定时任务,这会是个很大的问题,因为即使进行重试,也没有效果,除非你手动删除该目录

当然,这个问题并不大,最大的问题是,整个过程Hive表都无法正常对外提供服务了。我相信如果大家看完了我前面关于Delta Lake的篇章,应该自己能脑补为什么不会存在上面的问题。不过我这里还是聊一聊Delta Lake为什么不存在Hive的问题。

首先Delta Lake是有版本支持的,而且新数据写入(包括覆盖写),都不会影响原来的版本(我们先假设overwrite之前的最新版本是10),这意味着,Delta在进行overwrite操作时,他会先写新数据,把所有的准备工作做好,这个过程,所有的reader都读版本10的数据,读操作不会受到影响。接着,耗时的准备工作做好了,delta才会开始进行commit操作,也就是把这次新增的数据文件以及那些要标记删除的数据文件都记录下来,形成一个新的版本,这个过程是有原子性的,要么成功,要么失败,不会partial状态。所以commit失败了(比如没commit或者commit期间程序异常被杀),那么依然不影响读。当程序再次启动运行的时候,程序看到的依然是老版本10,这个时候他会重新进行之前的覆盖操作。

你可能会问,如果事变了,那那些准备好的数据在哪呢,不会被读取么?答案是他们变成了孤儿数据,相当于没有指针再指向了(Delta Log里没有他们的记录),可以回收掉了。Delta会在合适的时候自动收拾掉这些数据,或者你调用vacuum去手动清楚。

0 人点赞