WAL(Write Ahead Log)預寫日誌,是數據庫系統中常見的一種手段,用於保證數據操做的原子性和持久性。mysql
在計算機科學中,預寫式日誌(Write-ahead logging,縮寫 WAL)是關係數據庫系統中用於提供原子性和持久性(ACID 屬性中的兩個)的一系列技術。在使用 WAL 的系統中,全部的修改在提交以前都要先寫入 log 文件中。算法
log 文件中一般包括 redo 和 undo 信息。這樣作的目的能夠經過一個例子來講明。假設一個程序在執行某些操做的過程當中機器掉電了。在從新啓動時,程序可能須要知道當時執行的操做是成功了仍是部分紅功或者是失敗了。若是使用了 WAL,程序就能夠檢查 log 文件,並對忽然掉電時計劃執行的操做內容跟實際上執行的操做內容進行比較。在這個比較的基礎上,程序就能夠決定是撤銷已作的操做仍是繼續完成已作的操做,或者是保持原樣。sql
WAL 容許用 in-place 方式更新數據庫。另外一種用來實現原子更新的方法是 shadow paging,它並非 in-place 方式。用 in-place 方式作更新的主要優勢是減小索引和塊列表的修改。ARIES 是 WAL 系列技術經常使用的算法。在文件系統中,WAL 一般稱爲 journaling。PostgreSQL 也是用 WAL 來提供 point-in-time 恢復和數據庫複製特性。數據庫
咱們想想,若是想保證對一個數據的操做能夠恢復。能夠怎麼作?你不用去想數據庫是怎麼實現的,也不用想過高深。其實這是一個很簡單的問題,咱們經常在處理這種問題。最簡單的方法其實就是備份一份數據:當我須要對一條數據作更新操做前,先將這條數據備份在一個地方,而後去更新,若是更新失敗,能夠從備份數據中回寫回來。這樣就能夠保證事務的回滾,就能夠保證數據操做的原子性了。其實 SQLite 引入 WAL 以前就是經過這種方式來實現原子事務,稱之爲 rollback journal, rollback journal 機制的原理是:在修改數據庫文件中的數據以前,先將修改所在分頁中的數據備份在另一個地方,而後纔將修改寫入到數據庫文件中;若是事務失敗,則將備份數據拷貝回來,撤銷修改;若是事務成功,則刪除備份數據,提交修改。c#
再繼續上面的問題?如何作到數據的可恢復(原子性)和提交成功的數據被持久化到磁盤(持久性)?另外一種機制就是WAL,WAL 機制的原理也很簡單:修改並不直接寫入到數據庫文件中,而是寫入到另一個稱爲 WAL 的文件中;若是事務失敗,WAL 中的記錄會被忽略,撤銷修改;若是事務成功,它將在隨後的某個時間被寫回到數據庫文件中,提交修改。緩存
咱們都知道,數據庫的最大性能挑戰就是磁盤的讀寫,許多先輩在提供數據存儲性能上絞盡腦汁,提出和實驗了一套又一套方法。其實全部方案最終總結出來就三種:隨機讀寫改順序讀寫、緩衝單條讀寫改批量讀寫、單線程讀寫改併發讀寫。WAL 其實也是這兩種思路的一種實現,一方面 WAL 中記錄事務的更新內容,經過 WAL 將隨機的髒頁寫入變成順序的日誌刷盤,另外一方面,WAL 經過 buffer 的方式改單條磁盤刷入爲緩衝批量刷盤,再者從 WAL 數據到最終數據的同步過程當中能夠採用併發同步的方式。這樣極大提高數據庫寫入性能,所以,WAL 的寫入能力決定了數據庫總體性能的上限,尤爲是在高併發時。併發
上面講到,使用 WAL 的數據庫系統不會再每新增一條 WAL 日誌就將其刷入數據庫文件中,通常積累必定的量而後批量寫入,一般使用頁爲單位,這是磁盤的寫入單位。 同步 WAL 文件和數據庫文件的行爲被稱爲 checkpoint(檢查點),通常在 WAL 文件積累到必定頁數修改的時候;固然,有些系統也能夠手動執行 checkpoint。執行 checkpoint 以後,WAL 文件能夠被清空,這樣能夠保證 WAL 文件不會由於太大而性能降低。elasticsearch
有些數據庫系統讀取請求也可使用 WAL,經過讀取 WAL 最新日誌就能夠獲取到數據的最新狀態。分佈式
常見的數據庫通常都會用到 WAL 機制,只是不一樣的系統說法和實現可能有所差別。mysql、sqlite、postgresql、etcd、hbase、zookeeper、elasticsearch 等等都有本身的實現。高併發
mysql 的 WAL,你們可能都比較熟悉。mysql 經過 redo、undo 日誌實現 WAL。redo log 稱爲重作日誌,每當有操做時,在數據變動以前將操做寫入 redo log,這樣當發生掉電之類的狀況時系統能夠在重啓後繼續操做。undo log 稱爲撤銷日誌,當一些變動執行到一半沒法完成時,能夠根據撤銷日誌恢復到變動之間的狀態。mysql 中用 redo log 來在系統 Crash 重啓之類的狀況時修復數據(事務的持久性),而 undo log 來保證事務的原子性。
和大多數分佈式系統同樣,ZooKeeper 也有 WAL(Write-Ahead-Log),對於每個更新操做,ZooKeeper 都會先寫 WAL, 而後再對內存中的數據作更新,而後向 Client 通知更新結果。另外,ZooKeeper 還會按期將內存中的目錄樹進行 Snapshot,落地到磁盤上。這麼作的主要目的,一固然是數據的持久化,二是加快重啓以後的恢復速度,若是所有經過 Replay WAL 的形式恢復的話,會比較慢。
若是沒有用 fsync
把數據從文件系統緩存刷(flush)到硬盤,elasticsearch 不能保證數據在斷電甚至是程序正常退出以後依然存在。爲了保證可靠性,須要確保數據變化被持久化到磁盤。
在動態更新索引時,elasticsearch 說一次完整的提交會將段刷到磁盤,並寫入一個包含全部段列表的提交點。Elasticsearch 在啓動或從新打開一個索引的過程當中使用這個提交點來判斷哪些段隸屬於當前分片。
即便經過每秒刷新(refresh)實現了近實時搜索,elasticsearch 仍然須要常常進行完整提交來確保能從失敗中恢復。但在兩次提交之間發生變化的文檔怎麼辦?
Elasticsearch 增長了一個 translog ,或者叫事務日誌,在每一次對 Elasticsearch 進行操做時均進行了日誌記錄。
用過 etcd 的同窗可能會發現,etcd 的數據目錄下有兩個子目錄wal
和snap
。它們的做用就是實現 WAL 機制用的。
wal
: 存放預寫式日誌,最大的做用是記錄了整個數據變化的所有歷程。在 etcd 中,全部數據的修改在提交前,都要先寫入到 WAL 中。
snap
: 存放快照數據,etcd 防止 WAL 文件過多而設置的快照,存儲 etcd 數據狀態。
WAL 機制使得 etcd 具有了如下兩個功能:
hbase 實現 WAL 的方法將 HLog,hbase 的 RegionServer 會將數據保存在內存中(MemStore),直到知足必定條件,將其 flush 到磁盤上。這樣能夠避免建立不少小文件。內存存儲是不穩定的,HBase 也是使用 WAL 來解決這個問題:每次更新操做都會寫日誌,而且寫日誌和更新操做在一個事務中。
Mysql 大表問題和解決
Mysql 主鍵問題
列式存儲
時間序列數據庫(TSDB)初識與選擇
十分鐘瞭解 Apache Druid
Apache Druid 底層存儲設計
Apache Druid 的集羣設計與工做流程
想了解更多數據存儲相關知識,請關注個人公衆號。