概述
redis跟memcached類似,都是內存數據庫,不過redis支持數據持久化,也就是說redis可以將內存中的數據同步到磁盤來持久化,以確保redis 的數據安全。不過持久化這塊可能比較容易產生誤解,下面聊聊這塊。
Redis持久化是如何工作的?
什么是持久化?簡單來講就是將數據放到斷電后數據不會丟失的設備中,也就是我們通常理解的硬盤上。
1、數據庫寫操作的5個過程
首先我們來看一下數據庫在進行寫操作時到底做了哪些事,主要有下面五個過程:
- 客戶端向服務端發送寫操作(數據在客戶端的內存中)。
- 數據庫服務端接收到寫請求的數據(數據在服務端的內存中)。
- 服務端調用write這個系統調用,將數據往磁盤上寫(數據在系統內存的緩沖區中)。
- 操作系統將緩沖區中的數據轉移到磁盤控制器上(數據在磁盤緩存中)。
- 磁盤控制器將數據寫到磁盤的物理介質中(數據真正落到磁盤上)。
2、故障分析
寫操作大致有上面5個流程,當數據庫系統故障時,這時候系統內核還是完好的。那么此時只要我們執行完了第3步,那么數據就是安全的,因為后續操作系統會來完成后面幾步,保證數據最終會落到磁盤上。當系統斷電時,這時候上面5項中提到的所有緩存都會失效,并且數據庫和操作系統都會停止工作。所以只有當數據在完成第5步后,才能保證在斷電后數據不丟失。
【補充】這里可能有幾個疑問:
- 數據庫多長時間調用一次write,將數據寫到內核緩沖區?
- 內核多長時間會將系統緩沖區中的數據寫到磁盤控制器?
- 磁盤控制器又在什么時候把緩存中的數據寫到物理介質上?
對于第一個問題,通常數據庫層面會進行全面控制。
而對第二個問題,操作系統有其默認的策略,但是我們也可以通過POSIX API提供的fsync系列命令強制操作系統將數據從內核區寫到磁盤控制器上。
對于第三個問題,看起來數據庫已經無法觸及,但實際上,大多數情況下磁盤緩存是被設置關閉的,或者是只開啟為讀緩存,也就是說寫操作不會進行緩存,直接寫到磁盤。建議的做法是僅僅當你的磁盤設備有備用電池時才開啟寫緩存。
3、數據損壞
所謂數據損壞,就是數據無法恢復,上面我們講的都是如何保證數據是確實寫到磁盤上去,但是寫到磁盤上可能并不意味著數據不會損壞。比如我們可能一次寫請求會進行兩次不同的寫操作,當意外發生時,可能會導致一次寫操作安全完成,但是另一次還沒有進行。如果數據庫的數據文件結構組織不合理,可能就會導致數據完全不能恢復的狀況出現。
三種解決策略:
1)最粗糙的處理,就是不通過數據的組織形式保證數據的可恢復性。而是通過配置數據同步備份的方式,在數據文件損壞后通過數據備份來進行恢復。實際上MongoDB在不開啟操作日志,通過配置Replica Sets時就是這種情況。
2)在上面基礎上添加一個操作日志,每次操作時記一下操作的行為,這樣我們可以通過操作日志來進行數據恢復。因為操作日志是順序追加的方式寫的,所以不會出現操作日志也無法恢復的情況。這也類似于MongoDB開啟了操作日志的情況。
3)更保險的做法是數據庫不進行舊數據的修改,只是以追加方式去完成寫操作,這樣數據本身就是一份日志,這樣就永遠不會出現數據無法恢復的情況了。實際上CouchDB就是此做法的優秀范例。
那么,redis又針對持久化提供了什么方式呢?
redis持久化的兩種方式
redis提供了兩種持久化的方式,分別是RDB(Redis DataBase)和AOF(Append Only File)。
RDB,簡而言之,就是將存儲的數據快照的方式存儲到磁盤上,
AOF,則是將redis執行過的所有寫指令記錄下來,通過write函數追加到AOF文件的末尾。在下次redis重新啟動時,只要把這些寫指令從前到后再重復執行一遍,就可以實現數據恢復了。
RDB機制
1、概念
RDB持久化是指在指定的時間間隔內將內存中的數據集快照寫入磁盤。也是默認的持久化方式,這種方式是就是將內存中數據以快照的方式寫入到二進制文件中,默認的文件名為dump.rdb。