Delta Lake簡介

Delta Lake 是一個存儲層,爲 Apache Spark 和大數據 workloads 提供 ACID 事務能力,其通過寫和快照隔離之間的樂觀併發控制(optimistic concurrency control),在寫入數據期間提供一致性的讀取,從而爲構建在 HDFS 和雲存儲上的數據湖(data lakes)帶來可靠性。Delta Lake 還提供內置數據版本控制,以便輕鬆回滾。


爲什麼需要Delta Lake

現在很多公司內部數據架構中都存在數據湖,數據湖是一種大型數據存儲庫和處理引擎。它能夠存儲大量各種類型的數據,擁有強大的信息處理能力和處理幾乎無限的併發任務或工作的能力,最早由 Pentaho 首席技術官詹姆斯迪克森在2011年的時候提出。雖然數據湖在數據範圍方面邁出了一大步,但是也面臨了很多問題,主要概括如下:

  • 數據湖的讀寫是不可靠的。數據工程師經常遇到不安全寫入數據湖的問題,導致讀者在寫入期間看到垃圾數據。他們必須構建方法以確保讀者在寫入期間始終看到一致的數據。

  • 數據湖中的數據質量很低。將非結構化數據轉儲到數據湖中是非常容易的。但這是以數據質量爲代價的。沒有任何驗證模式和數據的機制,導致數據湖的數據質量很差。因此,努力挖掘這些數據的分析項目也會失敗。

  • 隨着數據的增加,處理性能很差。隨着數據湖中存儲的數據量增加,文件和目錄的數量也會增加。處理數據的作業和查詢引擎在處理元數據操作上花費大量時間。在有流作業的情況下,這個問題更加明顯。

  • 數據湖中數據的更新非常困難。工程師需要構建複雜的管道來讀取整個分區或表,修改數據並將其寫回。這種模式效率低,並且難以維護。

由於存在這些挑戰,許多大數據項目無法實現其願景,有時甚至完全失敗。我們需要一種解決方案,使數據從業者能夠利用他們現有的數據湖,同時確保數據質量。這就是 Delta Lake 產生的背景。

Delta Lake特性

Delta Lake 很好地解決了上述問題,以簡化我們構建數據湖的方式。

webp

image.png

支持ACID事務

Delta Lake 在多併發寫入之間提供 ACID 事務保證。每次寫入都是一個事務,並且在事務日誌中記錄了寫入的序列順序。

事務日誌跟蹤文件級別的寫入並使用樂觀併發控制,這非常適合數據湖,因爲多次寫入/修改相同的文件很少發生。在存在衝突的情況下,Delta Lake 會拋出併發修改異常以便用戶能夠處理它們並重試其作業。

Delta Lake 還提供強大的可序列化隔離級別,允許工程師持續寫入目錄或表,並允許消費者繼續從同一目錄或表中讀取。讀者將看到閱讀開始時存在的最新快照。

Schema管理

Delta Lake 自動驗證正在被寫的 DataFrame 模式是否與表的模式兼容。

  • 表中存在但 DataFrame 中不存在的列會被設置爲 null

  • 如果 DataFrame 中有額外的列在表中不存在,那麼該操作將拋出異常

  • Delta Lake 具有可以顯式添加新列的 DDL 和自動更新Schema 的能力

可伸縮的元數據處理

Delta Lake 將表或目錄的元數據信息存儲在事務日誌中,而不是存儲在元存儲(metastore)中。這使得 Delta Lake 能夠在固定的時間內列出大型目錄中的文件,並且在讀取數據時非常高效。

數據版本

Delta Lake 允許用戶讀取表或目錄之前的快照。當文件被修改文件時,Delta Lake 會創建較新版本的文件並保留舊版本的文件。當用戶想要讀取舊版本的表或目錄時,他們可以在 Apache Spark 的讀取 API 中提供時間戳或版本號,Delta Lake 根據事務日誌中的信息構建該時間戳或版本的完整快照。這允許用戶重現之前的數據,並在需要時將表還原爲舊版本的數據。

統一的批處理和流 sink

除了批處理寫之外,Delta Lake 還可以使用作爲 Apache Spark structured streaming 高效的流 sink。再結合 ACID 事務和可伸縮的元數據處理,高效的流 sink 現在支持許多接近實時的分析用例,而且無需維護複雜的流和批處理管道。

數據存儲格式採用開源 Apache Parquet

Delta Lake 中的所有數據都是使用 Apache Parquet 格式存儲,使 Delta Lake 能夠利用 Parquet 原生的高效壓縮和編碼方案。

更新和刪除

Delta Lake 支持 merge, update 和 delete 等 DML 命令。這使得數據工程師可以輕鬆地在數據湖中插入/更新和刪除記錄。 由於 Delta Lake 以文件級粒度跟蹤和修改數據,因此它比讀取和覆蓋整個分區或表更有效。

數據異常處理

Delta Lake 還將支持新的 API 來設置表或目錄的數據異常。工程師能夠設置一個布爾條件並調整報警閾值以處理數據異常。當 Apache Spark 作業寫入表或目錄時,Delta Lake 將自動驗證記錄,當數據存在異常時,它將根據提供的設置來處理記錄。

兼容 Apache Spark API

開發人員可以將 Delta Lake 與他們現有的數據管道一起使用,僅需要做一些細微的修改。

使用

CRUD

Table Batch Reads and Writes

Create a table

val data = spark.range(0, 5)data.write.format("delta").save("/tmp/delta-table")

// 分區表df.write.format("delta").partitionBy("date").save("/delta/events")

Read table

val df = spark.read.format("delta").load("/tmp/delta-table")df.show()

Update table

// overwriteval data = spark.range(5, 10)data.write.format("delta").mode("overwrite").save("/tmp/delta-table")

// updateimport io.delta.tables._import org.apache.spark.sql.functions._val deltaTable = DeltaTable.forPath("/tmp/delta-table")// Update every even value by adding 100 to itdeltaTable.update(
  condition = expr("id % 2 == 0"),
  set = Map("id" -> expr("id + 100")))// Delete every even valuedeltaTable.delete(condition = expr("id % 2 == 0"))// Upsert (merge) new dataval newData = spark.range(0, 20).as("newData").toDF

deltaTable.as("oldData")
  .merge(
    newData,
    "oldData.id = newData.id")
  .whenMatched  .update(Map("id" -> col("newData.id")))
  .whenNotMatched  .insert(Map("id" -> col("newData.id")))
  .execute()deltaTable.toDF.show()

// update by expressionsimport io.delta.tables._val deltaTable = DeltaTable.forPath(spark, pathToEventsTable)// predicate and update expressions using SQL formatted stringdeltaTable.updateExpr(            
  "eventType = 'clck'",
  Map("eventType" -> "'click'")

// mergedeltaTable  .as("logs")
  .merge(
    updates.as("updates"),
    "logs.uniqueId = updates.uniqueId")
  .whenNotMatched()
  .insertAll()
  .execute()

Delete table

import io.delta.tables._val deltaTable = DeltaTable.forPath(spark, pathToEventsTable)deltaTable.delete("date < '2017-01-01'")        // predicate using SQL formatted stringimport org.apache.spark.sql.functions._import spark.implicits._

deltaTable.delete($"date" < "2017-01-01")       // predicate using Spark SQL functions and implicits

流支持

Table Streaming Reads and Writes

查詢表的舊快照

Delta Lake 時間旅行允許您查詢 Delta Lake 表的舊快照。時間旅行有很多用例,包括:

  • 重新創建分析,報告或輸出(例如,機器學習模型的輸出)。這對於調試或審計非常有用,尤其是在受監管的行業中

  • 編寫複雜的臨時查詢

  • 修復數據中的錯誤

  • 爲快速更改的表的一組查詢提供快照隔離

DataFrameReader options 允許從 Delta Lake 表創建一個DataFrame 關聯到表的特定版本,可以使用如下兩種方式:

df1 = spark.read.format("delta").option("timestampAsOf", timestamp_string).load("/delta/events")df2 = spark.read.format("delta").option("versionAsOf", version).load("/delta/events")

對於timestamp_string,僅接受日期或時間戳字符串。例如,2019-01-012019-01-01 00:00:00.000Z

增加列

當以下任意情況爲 true 時,DataFrame 中存在但表中缺少的列將自動添加爲寫入事務的一部分:

  • write 或 writeStream 具有 .option("mergeSchema", "true")
    添加的列將附加到它們所在的結構的末尾。附加新列時將保留大小寫。

NullType 列

寫入 Delta 時,會從 DataFrame 中刪除 NullType 列(因爲 Parquet 不支持 NullType)。當收到該列的不同數據類型時,Delta Lake 會將 schema 合併到新數據類型

默認情況下,覆蓋表中的數據不會覆蓋 schema。 使用模式 overwrite 覆蓋表而不使用 replaceWhere 時,可能仍希望覆蓋正在寫入的數據的 schema。 可以通過設置以下內容來選擇替換表的 schema :

df.write.option("overwriteSchema", "true")

視圖

Transactional meta 實現

在文件上增加一個日誌結構化存儲(transaction log ),該日誌有序(ordered)且保持原子性(atomic)。

增加或者刪除數據時,都會產生一個描述文件,採用樂觀併發控制 (optimistic concurrency control) 保證用戶併發操作時數據的一致性。

webp

image.png

每次表更都生產一個描述文件,描述文件的記錄數和歷史版本數量一致。如圖,delta-table表13個歷史版本就有13個描述文件。

webp

image.png

webp

image.png

webp

image.png

併發控制

Delta Lake 在讀寫中提供了 ACID 事務保證。這意味着:

  • 跨多集羣的併發寫入,也可以同時修改數據集並查看錶的一致性快照,這些寫入操作將按照串行執行

  • 在作業執行期間修改了數據,讀取時也能看到一致性快照。

樂觀併發控制

Delta Lake 使用 optimistic concurrency control 機制提供寫數據時的事務保證,在這種機制下,寫過程包含三個步驟:

  1. Write: 通過編寫新數據文件來進行所有更改

  2. Validate and commit: 調用 commit 方法,生成 commit 信息,生成一個新的遞增1的文件,如果相同的文件名已經存在,則報 ConcurrentModificationException。

名詞解釋

ACID

ACID 就是指數據庫事務的四個基本要素,對應的是原子性 Atomicity,一致性 Consistency,隔離性 Isolation 和持久性 Durability。

  • 原子性: 一個事務要麼全部成功,要不全部失敗,事務出現錯誤會被回滾到事務開始時候的狀態。

  • 一致性: 系統始終處於一致的狀態,所有操作都應該服務現實中的期望。

  • 隔離性: 併發事務不會互相干擾,事務之間互相隔離。

  • 持久性: 事務結束後就一直保存在數據庫中,不會被回滾。

Snapshot

Snapshot 相當於當前數據的快照。這個快照包括的內容不僅僅只有一個版本號,還會包括當前快照下的數據文件,上一個 Snapshot 的操作,以及時間戳和 DeltaLog 的記錄。

MetaData

這裏是指 Delta Table 的元數據,包括 id,name,format,創建時間,schema 信息等等。

事務日誌

事務日誌的相關代碼主要在 org.apache.spark.sql.delta.DeltaLog 中。這個是 Delta Lake 把對數據/表的操作的記錄日誌。

CheckSum

可以說 CheckSum 是一個對象,裏面包含了,當前 SNAPSHOT 下的表的物理大小,文件數,MetaData 的數量,協議以及事務的數量。這些信息會轉成 Json 格式,存放在 CheckSumFile 中。

校驗文件是在 Snapshot 的基礎上計算的,會和各自的事務生死存亡。



作者:zfylin
鏈接:https://www.jianshu.com/p/c07c2791790d
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章