作者:吴文池
背景
iceberg提供合并小文件功能,可以按照用户的配置文件,把多个符合配置的小文件合并成多个大文件。该流程主要是对源数据做了一次复制。
但在实际生产环境中,数据是一直在变化的,有可能会出现这种情况:在还未完成数据合并任务时,对之前的数据做出了修改,这就导致正在合并的数据与新数据可能会产生冲突。
那么iceberg是如何处理这种数据冲突的呢?
iceberg行级删除
iceberg的行级修改主要是通过行级删除记录再加上数据记录实现的,所以下面先说一下iceberg行级删除的实现。
iceberg行级删除实现概要
iceberg的行级更新和删除,主要是通过增加delete记录做到的。iceberg总共有两种delete类型,一种是position delete,一种是equality delete,主要区别是在于该数据的插入和修改操作是否在同一个checkpoint内。此次分析的冲突场景主要是不同快照间的,所以以下说明都以equality delete为背景,简单说下流程(非upsert模式)。
先在 writer 中设置 equalityFieldColumns :
DataStreamSink append = FlinkSink.forRowData(input)
.tableLoader(tableLoader)
.overwrite(false)
.distributionMode(DistributionMode.HASH)
.equalityFieldColumns(Lists.newArrayList(“column1”, “column2”))
.append();
设置好之后,writer就会根据设置的列对数据做写入,如果是插入的数据,则写为数据记录,如果是删除数据,则写为删除记录(非upsert模式):
case INSERT:
case UPDATE_AFTER:
if (upsert) {
writer.delete(row);
}
writer.write(row);
break;
case UPDATE_BEFORE:
if (upsert) {
break; // UPDATE_BEFORE is not necessary for UPDATE, we do nothing to prevent delete one row twice
}
writer.delete(row);
break;
case DELETE:
writer.delete(row);
break;
在读取数据的时候,会根据数据生成的顺序(即sequenceNumber),判断该数据记录是否有对应的删除记录,如果有,则认为该数据已经被删除,如果没有,则认为该数据依然存在。
应用删除记录的判断条件