|
本篇博客是Redis系列的第3篇,主要講解下Redis的2種持久化機(jī)制:RDB和AOF。 本系列的前2篇可以點(diǎn)擊以下鏈接查看: Redis系列(一):Redis簡介及環(huán)境安裝。 Redis系列(二):Redis的5種數(shù)據(jù)結(jié)構(gòu)及其常用命令 1. 為什么需要持久化?因?yàn)镽edis是內(nèi)存數(shù)據(jù)庫,它將自己的數(shù)據(jù)存儲在內(nèi)存里面,一旦Redis服務(wù)器進(jìn)程退出或者運(yùn)行Redis服務(wù)器的計(jì)算機(jī)停機(jī),Redis服務(wù)器中的數(shù)據(jù)就會丟失。 為了避免數(shù)據(jù)丟失,所以Redis提供了持久化機(jī)制,將存儲在內(nèi)存中的數(shù)據(jù)保存到磁盤中,用于在Redis服務(wù)器進(jìn)程退出或者運(yùn)行Redis服務(wù)器的計(jì)算機(jī)停機(jī)導(dǎo)致數(shù)據(jù)丟失時(shí),快速的恢復(fù)之前Redis存儲在內(nèi)存中的數(shù)據(jù)。 Redis提供了2種持久化方式,分別為:
接下來,我們一一詳解。 2. RDB持久化RDB持久化是將某個(gè)時(shí)間點(diǎn)上Redis中的數(shù)據(jù)保存到一個(gè)RDB文件中,如下所示:
該文件是一個(gè)經(jīng)過壓縮的二進(jìn)制文件,通過該文件可以還原生成RDB文件時(shí)Redis中的數(shù)據(jù),如下所示:
2.1 創(chuàng)建RDB文件Redis提供了2個(gè)命令來創(chuàng)建RDB文件,一個(gè)是SAVE,另一個(gè)是BGSAVE。 SAVE命令會阻塞Redis服務(wù)器進(jìn)程,直到RDB文件創(chuàng)建完畢為止,在服務(wù)器進(jìn)程阻塞期間,服務(wù)器不能處理任何命令請求,如下所示:
BGSAVE命令會派生出一個(gè)子進(jìn)程,然后由子進(jìn)程負(fù)責(zé)創(chuàng)建RDB文件,服務(wù)器進(jìn)程(父進(jìn)程)繼續(xù)處理命令請求,如下所示:
以上描述也是這2個(gè)命令的區(qū)別,這里是重點(diǎn),面試經(jīng)常會問到。 因?yàn)锽GSAVE命令可以在不阻塞服務(wù)器進(jìn)程的情況下執(zhí)行,所以推薦使用BGSAVE命令。 我們可以手動執(zhí)行該命令,如上面截圖所示,但還是推薦設(shè)置下Redis服務(wù)器配置文件的save選項(xiàng),讓服務(wù)器每隔一段時(shí)間自動執(zhí)行一次BGSAVE命令。 我們可以通過save選項(xiàng)設(shè)置多個(gè)保存條件,只要其中任意一個(gè)條件被滿足,服務(wù)器就會執(zhí)行BGSAVE命令。 save選項(xiàng)設(shè)置的默認(rèn)條件如下所示:
默認(rèn)的配置條件表示,只要滿足以下3個(gè)條件中的任意1個(gè),BGSAVE命令就會被執(zhí)行:
當(dāng)滿足條件執(zhí)行BGSAVE命令時(shí),輸出日志如下圖所示:
生成的RDB文件會根據(jù)Redis配置文件中的名稱和路徑來保存,相關(guān)的2個(gè)配置如下所示:
最終生成的RDB文件如下所示(截圖為本機(jī)Windows環(huán)境,Linux環(huán)境下路徑會稍有不同):
2.2 載入RDB文件首先,我們要明確的是,載入RDB文件的目的是為了在Redis服務(wù)器進(jìn)程重新啟動之后還原之前存儲在Redis中的數(shù)據(jù)。 然后,Redis載入RDB文件并沒有專門的命令,而是在Redis服務(wù)器啟動時(shí)自動執(zhí)行的。 而且,Redis服務(wù)器啟動時(shí)是否會載入RDB文件還取決于服務(wù)器是否啟用了AOF持久化功能,具體判斷邏輯為:
以上判斷邏輯如下圖所示:
默認(rèn)情況下,Redis服務(wù)器的AOF持久化功能是關(guān)閉的,所以Redis服務(wù)器在啟動時(shí)會載入RDB文件, 啟動日志如下所示:
2.3 服務(wù)器狀態(tài)創(chuàng)建和載入RDB文件,可能存在的服務(wù)器狀態(tài)有以下3種:
3. AOF持久化AOF持久化是通過保存Redis服務(wù)器所執(zhí)行的寫命令來記錄數(shù)據(jù)庫數(shù)據(jù)的,如下圖所示:
默認(rèn)情況下,AOF持久化功能是關(guān)閉的,如果想要打開,可以修改下圖所示的配置:
舉個(gè)例子,假設(shè)Redis中還沒有存儲任何數(shù)據(jù),我們執(zhí)行了如下所示的命令:
然后我們會發(fā)現(xiàn)Redis服務(wù)器生成了1個(gè)名為appendonly.aof的文件,打開該文件,我們可以看到上面執(zhí)行的3個(gè)寫命令都存儲在該文件中:
3.1 AOF持久化的實(shí)現(xiàn)當(dāng)AOF持久化功能處于打開狀態(tài)時(shí),Redis服務(wù)器在執(zhí)行完一個(gè)寫命令之后,會以協(xié)議格式(如上面截圖中AOF文件里保存寫命令的格式)將被執(zhí)行的寫命令追加到服務(wù)器狀態(tài)的AOF緩沖區(qū)的末尾,然后Redis服務(wù)器會根據(jù)配置文件中appendfsync選項(xiàng)的值來決定何時(shí)將AOF緩沖區(qū)中的內(nèi)容寫入和同步到AOF文件里面。 appendfsync選項(xiàng)有以下3個(gè)值:
appendfsync選項(xiàng)的默認(rèn)值是everysec,也推薦使用這個(gè)值,因?yàn)榧缺WC了效率又保證了安全性。
3.2 載入AOF文件因?yàn)锳OF文件包含了重建數(shù)據(jù)庫所需的所有寫命令,所以Redis服務(wù)器只要讀入并重新執(zhí)行一遍AOF文件里面保存的寫命令,就可以還原Redis服務(wù)器關(guān)閉之前的數(shù)據(jù)。 Redis讀取AOF文件并還原數(shù)據(jù)庫的詳細(xì)步驟如下:
以上步驟如下圖所示:
如果Redis服務(wù)器開啟了AOF持久化功能,那么Redis服務(wù)器在啟動時(shí)會載入AOF文件, 啟動日志如下所示:
3.3 AOF重寫因?yàn)锳OF持久化是通過保存被執(zhí)行的寫命令來記錄數(shù)據(jù)庫數(shù)據(jù)的,所以隨著Redis服務(wù)器運(yùn)行時(shí)間的增加,AOF文件中的內(nèi)容會越來越多,文件的體積會越來越大,如果不做控制,會有以下2點(diǎn)壞處:
舉個(gè)例子,在客戶端執(zhí)行如下命令:
為了記錄這個(gè)list鍵的狀態(tài),AOF文件就需要保存上面執(zhí)行的6條命令。 為了解決AO文件體積越來越大的問題,Redis提供了AOF文件重寫功能,即Redis服務(wù)器會創(chuàng)建一個(gè)新的AOF文件來替代現(xiàn)有的AOF文件,新舊兩個(gè)AOF文件所保存的數(shù)據(jù)庫數(shù)據(jù)相同,但新AOF文件不會包含任何浪費(fèi)空間的冗余命令,所以新AOF文件的體積通常會比舊AOF文件的體積要小很多。 3.3.1 AOF重寫的實(shí)現(xiàn)原理AOF文件重寫并不需要對現(xiàn)有的AOF文件進(jìn)行任何讀取、分析或者寫入操作,而是通過讀取服務(wù)器當(dāng)前的數(shù)據(jù)庫數(shù)據(jù)來實(shí)現(xiàn)的。 仍然以上面的list鍵為例,舊的AOF文件保存了6條命令來記錄list鍵的狀態(tài),但list鍵的結(jié)果是“C” "D" "E" "F" "G"這樣的數(shù)據(jù),所以AOF文件重寫時(shí),可以用一條 按照上面的原理,如果Redis服務(wù)器存儲的鍵值對足夠多,AOF文件重寫生成的新AOF文件就會減少很多很多的冗余命令,進(jìn)而大大減小了AOF文件的體積。 綜上所述,AOF文件重寫功能的實(shí)現(xiàn)原理為: 首先從數(shù)據(jù)庫中讀取鍵現(xiàn)在的值,然后用一條命令去記錄鍵值對,代替之前記錄這個(gè)鍵值對的多條命令。 3.3.2 AOF后臺重寫因?yàn)锳OF文件重寫會進(jìn)行大量的文件寫入操作,所以執(zhí)行這個(gè)操作的線程將被長時(shí)間阻塞。 因?yàn)镽edis服務(wù)器使用單個(gè)線程來處理命令請求,所以如果由服務(wù)器進(jìn)程直接執(zhí)行這個(gè)操作,那么在重寫AOF文件期間,服務(wù)器將無法處理客戶端發(fā)送過來的命令請求。 為了避免上述問題,Redis將AOF文件重寫功能放到子進(jìn)程里執(zhí)行,這樣做有以下2個(gè)好處:
AOF后臺重寫的步驟如下所示:
Redis提供了
執(zhí)行完成后,打開appendonly.aof文件,發(fā)現(xiàn)保存list鍵的命令從六條變?yōu)榱艘粭l:
除了手動執(zhí)行
該配置表示,當(dāng)AOF文件的體積大于64MB,并且AOF文件的體積比上一次重寫之后的體積大了至少一倍(100%),Redis將自動執(zhí)行 4. RDB持久化、AOF持久化的區(qū)別通過上面的講解,我們會發(fā)現(xiàn)Redis提供的2種持久化方法是有區(qū)別的,可以總結(jié)為以下4點(diǎn):
接下來一一講解。 4.1 實(shí)現(xiàn)方式RDB持久化是通過將某個(gè)時(shí)間點(diǎn)Redis服務(wù)器存儲的數(shù)據(jù)保存到RDB文件中來實(shí)現(xiàn)持久化的。 AOF持久化是通過將Redis服務(wù)器執(zhí)行的所有寫命令保存到AOF文件中來實(shí)現(xiàn)持久化的。 4.2 文件體積由上述實(shí)現(xiàn)方式可知,RDB持久化記錄的是結(jié)果,AOF持久化記錄的是過程,所以AOF持久化生成的AOF文件會有體積越來越大的問題,Redis提供了AOF重寫功能來減小AOF文件體積。 4.3 安全性AOF持久化的安全性要比RDB持久化的安全性高,即如果發(fā)生機(jī)器故障,AOF持久化要比RDB持久化丟失的數(shù)據(jù)要少。 因?yàn)镽DB持久化會丟失上次RDB持久化后寫入的數(shù)據(jù),而AOF持久化最多丟失1s之內(nèi)寫入的數(shù)據(jù)(使用默認(rèn)everysec配置的話)。 4.4 優(yōu)先級由于上述的安全性問題,如果Redis服務(wù)器開啟了AOF持久化功能,Redis服務(wù)器在啟動時(shí)會使用AOF文件來還原數(shù)據(jù),如果Redis服務(wù)器沒有開啟AOF持久化功能,Redis服務(wù)器在啟動時(shí)會使用RDB文件來還原數(shù)據(jù),所以AOF文件的優(yōu)先級比RDB文件的優(yōu)先級高。 5. 源碼及參考Josiah L. Carlson 《Reids實(shí)戰(zhàn)》 黃健宏 《Redis設(shè)計(jì)與實(shí)現(xiàn)》 |
|
|