1. 程式人生 > >請問你知道分散式系統的預寫日誌設計模式麼?

請問你知道分散式系統的預寫日誌設計模式麼?

> 原文地址:https://martinfowler.com/articles/patterns-of-distributed-systems/wal.html # Write-Ahead log 預寫日誌 預寫日誌(WAL,Write-Ahead Log)將每次狀態更新抽象為**一個命令**並**追加**寫入一個日誌中,這個日誌只追加寫入,也就是順序寫入,所以 IO 會很快。相比於更新儲存的資料結構並且更新落盤這個隨機 IO 操作,寫入速度更快了,並且也提供了一定的永續性,也就是資料不會丟失,可以根據這個日誌恢復資料。 ## 背景介紹 如果遇到了伺服器儲存資料失敗,例如已經確認客戶端的請求,但是儲存過程中,重啟程序導致真正儲存的資料沒有落盤,在重啟後,也需要保證已經答應客戶端的請求資料更新真正落盤成功。 ## 解決方案 ![image](https://zhxhash-blog.oss-cn-beijing.aliyuncs.com/%E5%88%86%E5%B8%83%E5%BC%8F%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E9%A2%84%E5%86%99%E6%97%A5%E5%BF%97/wal.png) 將每一個更新,抽象為一個指令,並將這些指令儲存在一個檔案中。每個程序順序追加寫各自獨立的一個檔案,簡化了重啟後日志的處理,以及後續的線上更新操作。每個日誌記錄有一個獨立 id,這個 id 可以用來實現[分段日誌(Segmented Log)](https://zhuanlan.zhihu.com/p/257266256)或者[最低水位線(Low-Water Mark)](https://zhuanlan.zhihu.com/p/258082029)清理老的日誌。日誌更新可以使用[單一更新佇列(Singular Update Queue)]()這種設計模式。 日誌記錄的結構類似於: ``` class WALEntry { //日誌id private final Long entryId; //日誌內容 private final byte[] data; //型別 private final EntryType entryType; //時間 private long timeStamp; } ``` 在每次重新啟動時讀取日誌檔案,回放所有日誌條目來恢復當前資料狀態。 假設有一記憶體鍵值對資料庫: ``` class KVStore { pri