iT邦幫忙

2024 iThome 鐵人賽

DAY 18
2

https://ithelp.ithome.com.tw/upload/images/20241002/20168816esV7UNcfH8.png

我們從 Day 08 知道若從資料源的 OLTP 擷取資料變化送往資料倉儲這個 OLAP 系統進行加值運用,可能有全量、增量、SCD 等方式。再藉由 Day 17 的說明,我們開始有了串流處理的概念。兩個概念整合起來,就是資料變化要能即時反映出來,並透過事件的形式進行串接

變化偵測 (Change Detection)


OLTP 系統的資料變化偵測有以下幾種方法:

特定欄位偵測

例如用 updated_at 來表示資料的變更,讓下游可以透過這個欄位來獲取變化資料。但這方法需要應用開發者在應用程式內維護這個邏輯,且一旦資料源的資料被刪除,也沒有 updated_at 可以偵測了。

觸發器 (Trigger)

資料庫可以設定在指定事件如 INSERTUPDATEDELETE 發生時,將資料變更記錄到一個日誌表 (log table),這方法可以捕捉資料刪除的這個變化,也不需要應用開發者的配合。但它會造成資料事務 (transaction) 需要等待紀錄完成才能送出 (commit);同時需要維護一張表,當資料源發生大量變化時,這會成為很大的寫入負擔。

日誌基底的變更資料擷取 (Log-based CDC)

這個資料事務日誌是資料庫用來備份 (backup) 資料或做為異常時的援備 (recovery) 手段,亦或用於分散式 (distributed) 資料庫的主從節點資料同步。當然,寫入日誌比另外寫入一張表來的有效率多了!

Day 13 就有提到在資料倉儲裡,我們至少要有一份資料是完整記載任何收集進來的變動,不能覆蓋任何的歷史,這樣才保有日後需要進行資料回溯時的可重現性。看來有解了,我們只要能完整且即時地串接這份 log,就同時擁有了即時性與可重現性兩大優勢,而且還不太會影響 OLTP 的運作!

讀取日誌


為了追求效率,日誌本質上都是二進位或壓縮格式,因此直接原始資料並非人類直接可讀。不過每個資料庫系統都有工具可以將這些日誌轉換成可讀格式。我們就以幾個常見的關聯式資料庫 MySQL、PostgreSQL,和非關聯式資料庫 MongoDB 來說明吧!

MySQL

MySQL 的二進位日誌 binlog記錄了所有影響資料的修改操作。透過 mysqlbinlog 工具可以將這些日誌轉換為可讀格式。而在參數配置上,可分為

  • binlog-format=STATEMENT:把執行語句記錄下來。
  • binlog-format=ROW:把變更資料內容記錄下來。

可想而知,ROW 的記錄方法在大量更新資料時會造成大量日誌內容。

#230924 12:01:25 server id 1  Query   BEGIN
#230924 12:01:25 server id 1  Table_map: `test`.`users`
#230924 12:01:25 server id 1  Update_rows: table `test`.`users`
### UPDATE `test`.`users`
### WHERE @1=1 /* id */
###   @2='John' /* first_name */
### SET @2='Jonathan' /* first_name */
#230924 12:01:25 server id 1  COMMIT

這個 binlog 紀錄了一個 UPDATE 操作,修改 id = 1 的 user 的 first_name。
參考:MySQL Binary Logging Formats

PostgreSQL

預寫日誌記錄 (Write-Ahead Logging, WAL) 是確保資料完整性的標準方法。簡言之如果 WAL 記載變更之後到永久儲存,即便資料的更新未完成,我們還是能夠使用日誌來恢復資料庫。可以使用 pg_waldump 工具來讀取這些日誌。

rmgr: Heap        len (rec/tot):    44/   44, tx:   605, lsn: 0/1602C80, prev 0/1602C48, desc: INSERT off 3
BLOCK 0 OFFSET 3 TUPLE DATA: 0003 006a 6f6e 6168 616e
rmgr: Transaction len (rec/tot):    32/   32, tx:   605, lsn: 0/1602CB0, prev 0/1602C80, desc: COMMIT 2023-09-24 12:01:25.123 UTC

這段 WAL 記錄了一個事務,其中有一個 INSERT 操作。資料插入在某個表格的第 3 行 (off 3);插入的資料是二進位編碼 (006a 6f6e 6168 616e 代表 Jonathan )。該事務隨後在 2023-09-24 12:01:25 時間點被提交。
參考:PostgreSQL Write-Ahead Logging(WAL)

MongoDB 


Mongo 的操作日誌 operations log,存放在 oplog.rs 這個集合 (collection) 裡面,可以透過 mongo 的查詢語法來查看日誌資料。

{
   "ts" : Timestamp(1692957685, 1),
   "h" : NumberLong("1234567890123456789"),
   "v" : 2,
   "op" : "u",
   "ns" : "test.users",
   "o2" : { "_id" : 1 },
   "o" : { "$set" : { "first_name" : "Jonathan" } }
}

這個 oplog 記錄了 test.users 表中的一個 UPDATE 操作,將 id 為 1 的 firstname 改為 Jonathan。op: "u" 表示這是一個 UPDATE 操作。
不過 oplog 是為了讓分散式儲存系統的 Replica Sets 之間資料達到最終一致性而生的日誌。還可以透過 MongoDB 提供的高階 API db.collection.watch() 進行資料變更監控,也是一種方便的選擇。

參考:MongoDB Replica Set OplogMongoDB db.collection.watch()

拿到 log 的下一步


這些被捕捉到的變更或 CDC 日誌,都是從資料源所產生的衍生資料 (derived data),Day 05 提過的資料湖、資料倉儲、資料湖倉都是由衍生資料所搭建的系統,可統稱衍生資料系統。衍生資料系統的強大就在於它介接了各種不同的資料來源,成為一個彙集完整資訊的資料中心。

https://ithelp.ithome.com.tw/upload/images/20241002/201688167OOq4dF3ch.png

Source: https://medium.com/mercedes-benz-techinnovation-blog/change-data-capture-lessons-learnt-7976391cf78d

從上方這張圖 Mirrow DB 可以看見,這些變更日誌,本質上還是為了資料源本身的備份、故障援備機制而生。擁有日誌對於資料庫的重建是關鍵的存在。而對於資料倉儲或資料湖而言,衍生資料的取得只是分別以結構化或非結構化的方式存入系統,重點則是後續的加值運用。

今天就談到這。回顧第一段談的「資料變化要能即時反映出來,並透過事件的形式進行串接。」今天只提到資料變化而已,即時/事件/串接的操作技術留待明日分曉。


上一篇
《資料與程式碼的交鋒》Day 17 - 資料處理架構的抉擇
下一篇
《資料與程式碼的交鋒》Day 19 - 資料異動即時串接
系列文
資料與程式碼的交鋒 - Data Engineer 與合作夥伴的協奏曲 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言