請問你知道分散式系統的預寫日誌設計模式麼?
阿新 • • 發佈:2021-02-09
> 原文地址: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