深刻理解 Apache Spark Delta Lake 的事務日誌

深刻理解 Apache Spark Delta Lake 的事務日誌

過往記憶大數據 過往記憶大數據
Delta Lake 是今年數磚在 Spark+AI Summit 2019 會議上開源的項目,詳見【重磅 | Apache Spark 社區期待的 Delta Lake 開源了】,當時文章只是簡單介紹了下功能,本文將深刻介紹 Apache Spark Delta Lake 的事務日誌,經過本文咱們能夠了解 Delta Lake 的 ACID 是如何實現的,這些巧妙的設計很是值得咱們學習。
事務日誌是理解 Delta Lake 的關鍵,由於它是貫穿許多最重要功能的通用模塊,包括 ACID 事務、可擴展的元數據處理、時間旅行(time travel)等。本文咱們將探討事務日誌(Transaction Log)是什麼,它在文件級別是如何工做的,以及它如何爲多個併發讀取和寫入問題提供優雅的解決方案。html

事務日誌(Transaction Log)是什麼

Delta Lake 事務日誌(也稱爲 DeltaLog)是 Delta Lake 表上執行每次事務的有序記錄。具體形式以下:數據庫

深刻理解 Apache Spark Delta Lake 的事務日誌

事務日誌主要用途是什麼?

單一事實來源json

Delta Lake 構建於 Apache Spark™ 之上,容許多個寫和讀操做同時對給定表進行操做。爲了始終向用戶顯示正確的數據視圖,事務日誌可做爲單一事實來源(single source of truth) - 中央存儲庫,用於跟蹤用戶對錶所作的全部更改。緩存

當用戶第一次讀取 Delta Lake 表或在打開的表上運行一個新查詢,該表自上次讀取以來已被修改,Spark 會檢查事務日誌來查看已向表寫入的新事務,而後使用這些新更改更新最終用戶的表。這可確保用戶表的版本始終與最新查詢中的主記錄同步,而且用戶沒法對錶進行不一樣的,衝突的更改。微信

Delta Lake 上的原子性實現

原子性是 ACID 事務的四個屬性之一,它能夠保證在 Delta Lake 上執行的操做(如 INSERT 或 UPDATE )要麼所有成功要麼所有不成功。若是沒有此屬性,硬件故障或軟件錯誤很容易致使數據僅部分寫入表中,從而致使數據混亂或損壞。併發

事務日誌是 Delta Lake 可以提供原子性保證的機制。不管如何,若是它沒有記錄在事務日誌中,它就不會發生。經過只記錄徹底執行的事務,並使用該記錄做爲惟一的真相來源,事務日誌容許用戶對其數據進行推理;而且即便數據在 PB 級別上,咱們也能夠對這些數據的準確性高枕無憂。ide

事務日誌是如何工做的

將事務分解爲原子提交
每當用戶執行修改表的操做(例如插入、更新或刪除)時,Delta Lake 將該操做分解爲一系列由如下一個或多個操做組成的離散步驟:oop

  • Add file:添加一個數據文件;
  • Remove file:刪除一個數據文件;
  • Update metadata:更新表的元數據(例如更改表的名稱,模式或分區);
  • Set transaction:Structured Streaming 做業已經提交的具備給定 ID 的微批次記錄;
  • Change protocol:經過將事務日誌切換到最新的軟件協議來啓用新特性;
  • Commit info:包含有關提交的信息以及該操做是在什麼時候何地進行的。
    而後這些操做將按照有序的原子單位記錄在事務日誌中,稱爲提交。
    例如,假設用戶建立一個事務以向表中添加新列,並向其中添加更多數據。Delta Lake 會將該事務分解爲多個部分,一旦事務完成,就將它們添加到事務日誌中,以下所示:學習

  • Update metadata:更改模式以包含新列;
  • Add file:每一個添加的新文件。
    文件級別的事務日誌
    當用戶建立 Delta Lake 表時,將在 _delta_log 子目錄中自動建立該表的事務日誌。當他或她對該表進行更改時,這些更改將做爲有序的原子提交記錄在事務日誌中。 每一個提交都以 JSON 文件的形式寫出,從 000000.json 開始。對錶的其餘更改按升序數字順序生成後續 JSON 文件,因此下一次提交被寫入到 000001.json 文件,下下次修改寫入到 000002.json 文件,依此類推。

深刻理解 Apache Spark Delta Lake 的事務日誌

若是想及時瞭解Spark、Hadoop或者HBase相關的文章,歡迎關注微信公衆號:iteblog_hadoop
所以,若是咱們經過從數據文件 1.parquet 和 2.parquet 向表中添加記錄。該事務將自動添加到事務日誌中,並以 000000.json 的形式保存到磁盤。而後,咱們改變主意並決定刪除這些文件並添加一個新文件(3.parquet)。這些操做將記錄爲事務日誌中的下一個提交,也就是 000001.json,以下所示。大數據

深刻理解 Apache Spark Delta Lake 的事務日誌

若是想及時瞭解Spark、Hadoop或者HBase相關的文章,歡迎關注微信公衆號:iteblog_hadoop
儘管 1.parquet 和 2.parquet 再也不是咱們 Delta Lake 表的一部分,但它們的添加和刪除仍記錄在事務日誌中,由於這些操做是在咱們的表上執行的 - 儘管它們最終相互抵消了。 Delta Lake 仍然保留這樣的原子提交,以確保在須要審計表或使用「時間旅行」來查看錶在給定時間點的樣子時,咱們可以準確地作到這一點。
此外,即便咱們從表中刪除了基礎數據文件,Spark 也不會馬上從磁盤中刪除文件。用戶可使用 VACUUM 命令刪除再也不須要的文件。

使用檢查點文件(Checkpoint Files)快速從新計算狀態

一旦咱們提交了10次事務日誌,Delta Lake 就會在相同的 _delta_log 子目錄中以 Parquet 格式保存一個檢查點文件(如上面的 00000000000000000010.checkpoint.parquet 文件)。每 10 次提交 Delta Lake 會自動生成檢查點文件,這個是經過參數 checkpointInterval 參數設置。使用檢查點文件(Checkpoint Files)快速從新計算狀態

深刻理解 Apache Spark Delta Lake 的事務日誌

若是想及時瞭解Spark、Hadoop或者HBase相關的文章,歡迎關注微信公衆號:iteblog_hadoop
這些檢查點文件在某個時間點保存表的整個狀態 - 以原生的 Parquet 格式保存,Spark 能夠快速輕鬆地讀取。換句話說,它們爲 Spark reader 提供了一種「快捷方式」來徹底複製表的狀態,從而容許 Spark 避免從新處理可能存在的數千個低效的小 JSON 文件。
爲了提升速度,Spark能夠運行一個 listFrom 操做來查看事務日誌中的全部文件,快速跳轉到最新的檢查點文件,而且只處理自保存了最新的檢查點文件以來提交的JSON。
爲了演示這是如何工做的,假設咱們已經建立了提交,而且事務日誌已經記錄到 000007.json。Spark 加快了提交的速度,並在內存中自動緩存了表的最新版本。與此同時,其餘一些寫入者(多是您過於熱心的隊友)已經向表中寫入了新數據,並事務日誌已經記錄到 0000012.json 了。
爲了合併這些新事務並更新表的狀態,Spark 將運行 listFrom 方法來查看版本7以後對錶的新更改。
深刻理解 Apache Spark Delta Lake 的事務日誌
若是想及時瞭解Spark、Hadoop或者HBase相關的文章,歡迎關注微信公衆號:iteblog_hadoop
Spark能夠直接跳到最近的檢查點文件(上圖中的 0000010.checkpoint.parquet 文件),而不須要處理全部中間 JSON 文件,由於這個檢查點文件包含 commit #10 中表的整個狀態。如今,Spark 只需執行 0000011.json 和 0000012.json 的增量處理便可得到表的當前狀態。而後 Spark 將表的版本12的狀態緩存到內存中。經過遵循此工做流程,Delta Lake 可以使用 Spark 以高效的方式始終更新表的狀態。

處理多個併發的讀取和寫入

如今咱們已經在高層次上了解了事務日誌如何工做的,讓咱們來談談併發性。到目前爲止,咱們的示例主要涵蓋了用戶線性提交事務或至少沒有衝突的狀況。可是當 Delta Lake 處理多個併發讀寫時會發生什麼?

答案很簡單,因爲 Delta Lake 由 Apache Spark 提供支持,所以不只可讓多個用戶同時修改表 - 這是預期的。爲了處理這些狀況,Delta Lake 採用了樂觀的併發控制。

什麼是樂觀併發控制?

樂觀併發控制是一種處理併發事務的方法,它假定不一樣用戶對錶所作的事務(更改)能夠在不相互衝突的狀況下完成。它的速度快得使人難以置信,由於當處理 PB 級的數據時,用戶極可能同時處理數據的不一樣部分,從而容許他們同時完成不衝突的事務。

例如,假設你和我正在一塊兒玩拼圖遊戲。只要咱們都在作拼圖的不一樣部分——好比你在角落裏,我在邊緣上——咱們沒有理由不能同時作更大拼圖的那一部分,而且以兩倍的速度完成拼圖。只有當咱們同時須要相同的部件時,纔會產生衝突。這就是樂觀併發控制。

相反,一些數據庫系統使用悲觀鎖定的概念,這是假設最壞的狀況——即便咱們有10,000塊拼圖,在某個時候咱們確定須要相同的拼圖——這致使了太多的衝突。爲了解決這個問題,它的理由是,應該只容許一我的同時作拼圖,並把其餘人都鎖在房間外面。這不是一個快速(或友好)解決難題的方法!

固然,即便使用樂觀併發控制,有時用戶也會嘗試同時修改數據的相同部分。幸運的是,Delta Lake 有相應的協議處理它。

樂觀地解決衝突

爲了提供ACID事務,Delta Lake 有一個協議,用於肯定提交應該如何排序(在數據庫中稱爲 serializability),並肯定在同時執行兩個或多個提交時應該作什麼。Delta Lake經過實現互斥(mutual exclusion)規則來處理這些狀況,而後嘗試樂觀地解決任何衝突。該協議容許Delta Lake遵循ACID隔離原則,該原則確保多個併發寫操做以後的表的結果狀態與那些連續發生的寫操做相同,而且是彼此隔離的。

通常來講,這個過程是這樣進行的

  • 記錄起始表的版本;
  • 記錄讀和寫操做;
  • 嘗試提交;
  • 若是有人已經提交了,檢查一下你讀到的內容是否有變化;
  • 重複上面的步驟。
    爲了瞭解這一切是如何實時進行的,讓咱們看一下下面的圖表,看看 Delta Lake 在衝突忽然出現時是如何管理衝突的。假設兩個用戶從同一個表中讀取數據,而後每一個用戶都嘗試向表中添加一些數據。

深刻理解 Apache Spark Delta Lake 的事務日誌
若是想及時瞭解Spark、Hadoop或者HBase相關的文章,歡迎關注微信公衆號:iteblog_hadoop

  • Delta Lake 記錄在進行任何更改以前讀取的表的起始表版本(版本0);
  • 用戶1和2都試圖同時向表添加一些數據。在這裏,咱們遇到了一個衝突,由於接下來只有一個提交能夠被記錄爲 000001.json;
  • Delta Lake使用「互斥」概念處理這種衝突,這意味着只有一個用戶可以成功提交 000001.json。用戶1的提交被接受,而用戶2的提交被拒絕;
  • Delta Lake 更傾向於樂觀地處理這種衝突,而不是爲用戶2拋出錯誤。它檢查是否對錶進行了任何新的提交,並悄悄地更新表以反映這些更改,而後在新更新的表上重試用戶2的提交(不進行任何數據處理),最後成功提交 000002.json。
    在絕大多數狀況下,這種和解是悄無聲息地、完美無缺地、成功地進行的。可是,若是 Delta Lake 沒法樂觀地解決不可調和的問題(例如,若是用戶1刪除了用戶2也刪除的文件),那麼唯一的選擇就是拋出一個錯誤。
    最後要注意的是,因爲在 Delta Lake 表上進行的全部事務都直接存儲到磁盤中,所以這個過程知足 ACID 持久性的特性,這意味着即便在系統發生故障時,它也會保持。

    其餘用戶案例

    時間旅行(Time Travel)

    每一個表都是事務日誌中記錄的全部提交的總和的結果—很少也很多。事務日誌提供了一步一步的指導,詳細描述瞭如何從表的原始狀態轉換到當前狀態。

所以,咱們能夠經過從原始表開始從新建立表在任什麼時候間點的狀態,而且只處理在該點以前提交的數據。這種強大的功能被稱爲「時間旅行」,或數據版本控制,在任何狀況下都是救星。有關更多信息,請參考介紹大型數據湖的 Delta 時間旅行。

數據血統(Data Lineage)和調試

做爲對 Delta Lake 表所作的每一個更改的最終記錄,事務日誌爲用戶提供了可驗證的數據血統,這對於治理、審計和合規性目的很是有用。它還能夠用於跟蹤一個意外更改或管道中的一個 bug 的起源,以追溯到致使該更改的確切操做。用戶能夠運行 DESCRIBE HISTORY 來查看所作更改的元數據。

總結

在本博客中,咱們深刻研究 Delta Lake 事務日誌的工做原理。咱們討論了:

  • 事務日誌是什麼,它是如何構造的,以及提交如何做爲文件存儲在磁盤上;
  • 事務日誌如何做爲一個單一的事實來源,容許 Delta Lake 實現原子性原則;
  • Delta Lake 如何計算每一個表的狀態——包括它如何使用事務日誌來跟蹤最近的檢查點,以及它如何解決「小文件」問題;
  • 經過使用 Apache Spark 的強大功能來大規模處理元數據;
  • 使用樂觀併發控制容許多個併發讀和寫,即便在表發生更改時也是如此;
  • Delta Lake 如何使用互斥來確保正確地線性(serialized)提交,以及在發生衝突時如何默默地重試提交。
    本文翻譯自:Diving Into Delta Lake: Unpacking The Transaction Log
    https://databricks.com/blog/2019/08/21/diving-into-delta-lake-unpacking-the-transaction-log.html
    中文原文:https://www.iteblog.com/archives/2582.html
相關文章
相關標籤/搜索