iceberg合併小檔案衝突測試

努力爬呀爬發表於2022-02-24

基於iceberg的master分支的9b6b5e0d2(2022-2-9)。

引數說明

1、PARTIAL_PROGRESS_ENABLED(partial-progress.enabled)
預設為 false。該引數能夠讓合併任務以group為單位做提交,當其中一個group任務失敗,可以單獨對該group任務重試。

2、USE_STARTING_SEQUENCE_NUMBER(use-starting-sequence-number)
預設為 true。
該引數使用做合併時的sequenceNumber作為新的資料檔案的sequenceNumber。

測試

一、append方式生成 a,b,c三個snapshot,基於b做檔案合併。

模擬的場景是:已存在a,b快照,現在基於b快照做小檔案合併,但任務還未完成時,另一條資料流基於b快照做了append型別的資料:

右:USE_STARTING_SEQUENCE_NUMBER,下:PARTIAL_PROGRESS_ENABLED true false
true 成功 成功
false 成功 成功
  • 成功:生成新的快照,最終snapshot是 a,b,c,d。

  • 新生成的大檔案是基於a,b的資料檔案的總和,

  • 快照d中包含了c的資料,以及基於a,b合併的資料。

  • a,b,c,d對應的squenceNumber分別是1,2,3,4:
    USE_STARTING_SEQUENCE_NUMBER 為 true時,d裡面生成的新的大檔案對應的manifest的squeceid是用的以前的2,刪除的manifest用的是新的id4

    USE_STARTING_SEQUENCE_NUMBER 為 false 時,d裡面合併任務使用的全都是最新的id

結論:
1、純append流的資料,做小檔案合併都能成功。
2、可以通過設定 USE_STARTING_SEQUENCE_NUMBER 欄位來控制合併任務中的manifest的squencyNumber。

二、append方式生成 a,b,c 三個 snapshot,先基於c做一次合併,合併成功後,基於c再做一次合併。

模擬的場景是,基於c快照做小檔案合併,該任務還未完成,又啟動了一個基於c快照做小檔案合併的任務:

右:USE_STARTING_SEQUENCE_NUMBER,下:PARTIAL_PROGRESS_ENABLED true false
true 成功,但沒生成新快照 成功,但沒生成新快照
false 失敗 失敗
  • 成功,但沒生成新快照:只是表示該任務是完整執行了,沒有出現異常退出的情況,但最終並未生成新的快照。PARTIAL_PROGRESS_ENABLED 設定 true,會列印出異常資訊,但由於是部分提交,這些異常被忽略,最終程式執行成功,但也沒有生成新的 snapshot。Failure during rewrite commit process, partial progress enabled. Ignoring。
  • 失敗:提示 Cannot commit rewrite because of a ValidationException or CommitFailedException. This usually means that this rewrite has conflicted with another concurrent Iceberg operation. To reduce the likelihood of conflicts, set partial-progress.enabled which will break up the rewrite into multiple smaller commits controlled by partial-progress.max-commits. Separate smaller rewrite commits can succeed independently while any commits that conflict with another Iceberg operation will be ignored. This mode will create additional snapshots in the table history, one for each commit.

結論:目前功能上不能基於同一個快照做多次合併,只會成功一次。

三、append方式生成 a,b 兩個snapshot,對a的資料做更新生成c,再基於b做檔案合併。

模擬的場景是:基於b快照做合併,此時還未完成,另一條資料流對a快照中的資料做了更新,且提交成功生成了c快照:

右:USE_STARTING_SEQUENCE_NUMBER,下:PARTIAL_PROGRESS_ENABLED true false
true 成功 成功,但沒生成新快照
false 成功 失敗
  • 失敗:提示 Cannot commit, found new delete for replaced data file。
  • 成功,生成最新快照d,生成快照a,b中資料合併的大檔案
  • 成功,但沒生成新的快照:參考上面說明

結論:在合併的過程中,有另一條資料流對需要合併的資料做修改,可以通過設定 USE_STARTING_SEQUENCE_NUMBER 來使任務成功。

四、append方式生成 a,b,c 三個snapshot,對c的資料做更新生成d,再基於b做檔案合併。

模擬的場景:基於b快照做合併,此時還未完成,另一條資料流先做append,生成了c快照,然後又對c快照裡的資料做修改生成了快照d:

右:USE_STARTING_SEQUENCE_NUMBER,下:PARTIAL_PROGRESS_ENABLED true false
true 成功 成功,但沒生成新快照
false 成功 失敗
  • 失敗,提示:
    Cannot commit, found new delete for replaced data file
    Cannot commit rewrite because of a ValidationException or CommitFailedException. This usually means that this rewrite has conflicted with another concurrent Iceberg operation. To reduce the likelihood of conflicts, set partial-progress.enabled which will break up the rewrite into multiple smaller commits controlled by partial-progress.max-commits. Separate smaller rewrite commits can succeed independently while any commits that conflict with another Iceberg operation will be ignored. This mode will create additional snapshots in the table history, one for each commit.

因為在獲取檔案的時候,此時只能讀取到a和b下的資料檔案,a和b下沒有delete檔案,所以沒有讀取a和b下資料檔案的min和max。 在做merge的時候,最新的snapshot是d,此時有delete檔案,所以需要判斷該delete檔案是否能夠匹配上前面讀取的資料檔案。匹配條件有兩個,一個是sequenceNumber,一個是最大最小值是否有交集。delete的檔案是後生成的,它的sequenceNumber肯定是大於前面a,b下的資料檔案,所以該條件滿足。因為在讀取a,b下的資料檔案的時候,沒有讀取min,max,導致不能夠跟delete檔案做值的交叉範圍判斷,所以data檔案中被關聯了delete檔案,所以這種情況下,雖然只對 a和b做合併,且後續修改的資料檔案沒有被修改,但依然會合並失敗。
如果在讀取a,b下資料檔案的時候,把對應的min,max也讀取上來,那麼就可以合併成功,對應流程在 ManifestGroup.planFiles中,讀取內容由 columns 決定。

  • 成功:生成最新快照e,最終的快照為:a,b,c,d,e
  • 成功,但沒生成新的快照:參考上面說明

結論:雖然後續修改的資料並不在合併的資料中,但USE_STARTING_SEQUENCE_NUMBER為false依然會失敗,具體原因已在上面說明。

結論

1、PARTIAL_PROGRESS_ENABLED
當該引數為true時,雖然它最終能讓任務執行完成,但實際上它忽略子提交失敗的情況,所以實際有沒有做合併與該引數無關。

2、USE_STARTING_SEQUENCE_NUMBER
設定該引數為true,可以修改新生成的dataFile和manifest的sequenceNumber為原來的number,這樣在讀取資料的時候,就可以把delteFile應用到新生成的dataFile中了,可以解決大多數資料衝突的情況。

相關文章