詳解Redis持久化(RDB和AOF)

詳解Redis持久化(RDB和AOF)

什么是Redis持久化?

Redis讀寫速度快、性能優(yōu)越是因?yàn)樗鼘⑺袛?shù)據(jù)存在了內(nèi)存中,然而,當(dāng)Redis進(jìn)程退出或重啟后,所有數(shù)據(jù)就會丟失。所以我們希望Redis能保存數(shù)據(jù)到硬盤中,在Redis服務(wù)重啟之后,原來的數(shù)據(jù)能夠恢復(fù),這個過程就叫持久化。

Redis持久化的兩種方式?RDB和AOF

AOF:會將每次執(zhí)行的命令及時保存到硬盤中,實(shí)時性更好,丟失的數(shù)據(jù)更少

RDB:會根據(jù)指定的規(guī)則定時將內(nèi)存中的數(shù)據(jù)保存到硬盤中。

通常兩種方式結(jié)合使用,下面詳細(xì)介紹RDB和AOF

AOF

Append Only File,AOF會保存服務(wù)器執(zhí)行的所有寫操作到日志文件中,在服務(wù)重啟以后,會執(zhí)行這些命令來恢復(fù)數(shù)據(jù)。

日志文件默認(rèn)為appendonly.aof,Redis以Redis協(xié)議格式將命令保存至aof日志文件末尾,aof文件還會被重寫,使aof文件的體積不會大于保存數(shù)據(jù)集狀態(tài)所需要的實(shí)際大小

默認(rèn)情況下,aof沒有被開啟。需要在redis.conf開啟

appendonly yes

日志文件名

appendfilename "appendonly.aof"

日志文件所在目錄(RDB日志文件也是在這里)

dir ./

fsync持久化策略

appendfsync everysec

always:命令寫入aof_buf后立即調(diào)用系統(tǒng)fsync操作同步到AOF文件,fsync完成后線程返回。這種情況下,每次有寫命令都要同步到AOF文件,硬盤IO成為性能瓶頸,Redis只能支持大約幾百TPS寫入,嚴(yán)重降低了Redis的性能;即便是使用固態(tài)硬盤(SSD),每秒大約也只能處理幾萬個命令,而且會大大降低SSD的壽命。

no:命令寫入aof_buf后調(diào)用系統(tǒng)write操作,不對AOF文件做fsync同步;同步由操作系統(tǒng)負(fù)責(zé),通常同步周期為30秒。這種情況下,文件同步的時間不可控,且緩沖區(qū)中堆積的數(shù)據(jù)會很多,數(shù)據(jù)安全性無法保證。

everysec:命令寫入aof_buf后調(diào)用系統(tǒng)write操作,write完成后線程返回;fsync同步文件操作由專門的線程每秒調(diào)用一次。everysec是前述兩種策略的折中,是性能和數(shù)據(jù)安全性的平衡,因此是Redis的默認(rèn)配置,也是我們推薦的配置。

其余參數(shù):

● no-appendfsync-on-rewrite no:在重寫 AOF 文件的過程中,是否禁止 fsync。如果這個參數(shù)值設(shè)置為 yes(開啟),則可以減輕重寫 AOF 文件時 CPU 和硬盤的負(fù)載,但同時可能會丟失重寫 AOF 文件過程中的數(shù)據(jù);需要在負(fù)載與安全性之間進(jìn)行平衡。

● auto-aof-rewrite-percentage 100:指定 Redis 重寫 AOF 文件的條件,默認(rèn)為 100,它會對比上次生成的 AOF 文件大小。如果當(dāng)前 AOF 文件的增長量大于上次 AOF 文件的 100%,就會觸發(fā)重寫操作;如果將該選項(xiàng)設(shè)置為 0,則不會觸發(fā)重寫操作。

● auto-aof-rewrite-min-size 64mb:指定觸發(fā)重寫操作的 AOF 文件的大小,默認(rèn)為 64MB。如果當(dāng)前 AOF 文件的大小低于該值,此時就算當(dāng)前文件的增量比例達(dá)到了 auto-aof-rewrite-percentage 選項(xiàng)所設(shè)置的條件,也不會觸發(fā)重寫操作。換句話說,只有同時滿足以上這兩個選項(xiàng)所設(shè)置的條件,才會觸發(fā)重寫操作。

● auto-load-truncated yes:當(dāng) AOF 文件結(jié)尾遭到損壞時,Redis 在啟動時是否仍加載 AOF 文件。

AOF持久化的實(shí)現(xiàn)

(1)命令追加(append):Redis 服務(wù)器每執(zhí)行一條寫命令,這條寫命令都會被追加到緩存區(qū) aof_buf 中。(避免每次執(zhí)行的命令都直接寫入硬盤中,會導(dǎo)致硬盤 I/O 的負(fù)載過大,使得性能下降。)

命令追加的格式使用 Redis 命令請求的協(xié)議格式

file

(2)AOF 持久化文件寫入(write)和文件同步(sync):根據(jù) appendfsync 參數(shù)設(shè)置的不同的同步策略,將緩存區(qū) aof_buf 中的數(shù)據(jù)內(nèi)容同步到硬盤中。

先了解操作系統(tǒng)的 write 和 fsync 函數(shù)。為了提高文件的寫入效率,當(dāng)用戶調(diào)用 write 函數(shù)將數(shù)據(jù)寫入文件中時,操作系統(tǒng)會將這些數(shù)據(jù)暫存到一個內(nèi)存緩存區(qū)中,當(dāng)這個緩存區(qū)被填滿或者超過了指定時限后,才會將緩存區(qū)中的數(shù)據(jù)寫入硬盤中,這樣做既提高了效率,又保證了安全性。

Redis 的服務(wù)器進(jìn)程是一個事件循環(huán)(loop),這個事件循環(huán)中的文件事件負(fù)責(zé)接收客戶端的命令請求,處理之后,向客戶端發(fā)送命令回復(fù);而其中的時間事件則負(fù)責(zé)執(zhí)行像 serverCron 函數(shù)這樣需要定時運(yùn)行的函數(shù)。

服務(wù)器在處理文件事件時,可能會執(zhí)行客戶端發(fā)送過來的寫命令,使得一些命令被追加到緩存區(qū) aof_buf 中。因此,在服務(wù)器每次結(jié)束一個事件循環(huán)之前,都會調(diào)用 flushAppendOnlyFile 函數(shù),來決定是否將緩存區(qū) aof_buf 中的數(shù)據(jù)寫入和保存到 AOF 文件中。

flushAppendOnlyFile 函數(shù)的運(yùn)行與服務(wù)器配置的 appendfsync 參數(shù)有關(guān)。

AOF文件的重寫

AOF文件定期重寫,以達(dá)到壓縮的目的。

AOF文件過于龐大,會影響Redis的寫入速度,在執(zhí)行數(shù)據(jù)恢復(fù)時,也非常滿。AOF文件重寫就是解決這個問題。

AOF 文件重寫就是把 Redis 進(jìn)程內(nèi)的數(shù)據(jù)轉(zhuǎn)化為寫命令,然后同步到新的 AOF 文件中。在重寫的過程中,Redis 服務(wù)器會創(chuàng)建一個新的 AOF 文件來替代現(xiàn)有的 AOF 文件,新、舊兩個 AOF 文件所保存的數(shù)據(jù)庫狀態(tài)相同,但是新的 AOF 文件不會包含冗余命令。

AOF 文件重寫并不會對舊的 AOF 文件進(jìn)行讀取、寫入操作,這個功能是通過讀取服務(wù)器當(dāng)前的數(shù)據(jù)庫狀態(tài)來實(shí)現(xiàn)的。

舉例說明:

? 比如Redis使用五條rpush命令分別插入五種顏色

rpush color 〝yellow〝
rpush color 〝green〝
...

? AOF重寫后

 RPUSH color 〝yellow〝 〝green〝 〝black〝 〝pink〝〝white〝

所以AOF重寫的原理:

● AOF 文件重寫功能會丟棄過期的數(shù)據(jù),也就是過期的數(shù)據(jù)不會被寫入 AOF 文件中。

● AOF 文件重寫功能會丟棄無效的命令,無效的命令將不會被寫入 AOF 文件中。無效命令包括重復(fù)設(shè)置某個鍵值對時的命令、刪除某些數(shù)據(jù)時的命令等。

● AOF 文件重寫功能可以將多條命令合并為一條命令,然后寫入 AOF 文件中。

怎么觸發(fā)AOF重寫?

● 手動觸發(fā):執(zhí)行 BGREWRITEAOF 命令觸發(fā) AOF 文件重寫。該命令與 BGSAVE 命令相似,都是啟動(fork)子進(jìn)程完成具體的工作,且都在啟動時阻塞。

● 自動觸發(fā):自動觸發(fā) AOF 文件重寫是通過設(shè)置 Redis 配置文件中 auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size 參數(shù)的值,以及 aof_current_size 和 aof_base_size 狀態(tài)來確定何時觸發(fā)的。

auto-aof-rewrite-percentage 參數(shù)是在執(zhí)行 AOF 文件重寫時,當(dāng)前 AOF 文件的大?。╝of_current_size)和上一次 AOF 文件重寫時的大?。╝of_base_size)的比值,默認(rèn)為 100。

auto-aof-rewrite-min-size 參數(shù)設(shè)置了執(zhí)行 AOF 文件重寫時的最小體積,默認(rèn)為 64MB。

AOF文件的后臺重寫:

AOF重寫執(zhí)行大量的寫入操作,就會使得這個函數(shù)的線程被長時間阻塞。Redis 服務(wù)器使用單線程來處理命令請求。如果讓服務(wù)器直接調(diào)用 aof_rewrite 重寫函數(shù),那么在 AOF 文件重寫期間,服務(wù)器將不能繼續(xù)執(zhí)行其他命令,就會一直處于阻塞狀態(tài)。

Redis 將 AOF 文件重寫程序放到了一個子進(jìn)程中執(zhí)行,這樣做的好處是:

● 子進(jìn)程在執(zhí)行 AOF 文件重寫的過程中,Redis 服務(wù)器進(jìn)程可以繼續(xù)處理新的命令請求。

● 子進(jìn)程帶有服務(wù)器進(jìn)程的數(shù)據(jù)副本,使用子進(jìn)程可以在使用鎖的情況下,保證數(shù)據(jù)的安全性。

使用子進(jìn)程會導(dǎo)致數(shù)據(jù)庫狀態(tài)不一致,原因是:當(dāng)子進(jìn)程進(jìn)行 AOF 文件重寫的時候,Redis 服務(wù)器可以繼續(xù)執(zhí)行來自客戶端的命令請求,就會有新的命令對現(xiàn)有數(shù)據(jù)庫狀態(tài)進(jìn)行修改,進(jìn)而使得服務(wù)器當(dāng)前的數(shù)據(jù)庫狀態(tài)與重寫的 AOF 文件所保存的數(shù)據(jù)庫狀態(tài)不一致。

為了解決使用子進(jìn)程導(dǎo)致數(shù)據(jù)庫狀態(tài)不一致的問題,Redis 服務(wù)器設(shè)置了一個 AOF 文件重寫緩存區(qū)。這個 AOF 文件重寫緩存區(qū)在服務(wù)器創(chuàng)建子進(jìn)程之后開始使用,可以利用它來解決數(shù)據(jù)庫狀態(tài)不一致的問題。當(dāng) Redis 服務(wù)器成功執(zhí)行完一條寫命令后,它會同時將這條寫命令發(fā)送給 AOF 文件緩存區(qū)(aof_buf)和 AOF 文件重寫緩存區(qū)。

子進(jìn)程在執(zhí)行 AOF 文件重寫的過程中,服務(wù)器進(jìn)程的執(zhí)行過程如下:

(1)服務(wù)器接收到來自客戶端的命令請求,并成功執(zhí)行。

(2)服務(wù)器將執(zhí)行后的寫命令轉(zhuǎn)化為對應(yīng)的協(xié)議格式,然后追加到 AOF 文件緩存區(qū)(aof_buf)中。

(3)服務(wù)器再將執(zhí)行后的寫命令追加到 AOF 文件重寫緩存區(qū)中。

file

有了 AOF 文件重寫緩存區(qū),就可以保證數(shù)據(jù)庫狀態(tài)的一致性。AOF 文件緩存區(qū)的內(nèi)容會被定期寫入和同步到 AOF 文件中,AOF 文件的寫入和同步不會因?yàn)?AOF 文件重寫緩存區(qū)的引入而受到影響。當(dāng)服務(wù)器創(chuàng)建子進(jìn)程之后,服務(wù)器執(zhí)行的所有寫命令都會同時被追加到 AOF 文件緩存區(qū)和 AOF 文件重寫緩存區(qū)中。

如果子進(jìn)程完成了 AOF 文件重寫的工作,它就會發(fā)送一個完成信號給父進(jìn)程。當(dāng)父進(jìn)程接收到這個信號后,就會調(diào)用信號處理函數(shù),繼續(xù)執(zhí)行以下工作:

(1)將 AOF 文件重寫緩存區(qū)中的所有內(nèi)容寫入新的 AOF 文件中。新的 AOF 文件所保存的數(shù)據(jù)庫狀態(tài)與服務(wù)器當(dāng)前的數(shù)據(jù)庫狀態(tài)保持一致。

(2)修改新的 AOF 文件的文件名,新生成的 AOF 文件將會覆蓋現(xiàn)有(舊)的 AOF 文件,完成新、舊兩個文件的互換。

在完成上述兩個步驟之后,就完成了一次 AOF 文件后臺重寫工作。

在整個 AOF 文件后臺重寫的過程中,只有在信號處理函數(shù)執(zhí)行的過程中,服務(wù)器進(jìn)程才會被阻塞,在其他時候不存在阻塞情況。

AOF文件恢復(fù)數(shù)據(jù)的過程

(1)創(chuàng)建一個偽客戶端,用于執(zhí)行 AOF 文件中的寫命令。這個偽客戶端是一個不帶網(wǎng)絡(luò)連接的客戶端。因?yàn)橹荒茉诳蛻舳说纳舷挛闹胁拍軋?zhí)行 Redis 的命令,而在 AOF 文件中包含了 Redis 服務(wù)器啟動加載 AOF 文件時所使用的所有命令,而不是網(wǎng)絡(luò)連接,所以服務(wù)器創(chuàng)建了一個不帶網(wǎng)絡(luò)連接的偽客戶端來執(zhí)行 AOF 文件中的寫命令。

(2)讀取 AOF 文件中的數(shù)據(jù),分析并提取出 AOF 文件所保存的一條寫命令。

(3)使用偽客戶端執(zhí)行被讀取出的寫命令。

(4)重復(fù)執(zhí)行步驟(2)和(3),直到將 AOF 文件中的所有命令讀取完畢,并成功執(zhí)行為止。這個過程完成之后,就可以將服務(wù)器的數(shù)據(jù)庫狀態(tài)還原為關(guān)閉之前的狀態(tài)。

file

如果在 Redis 服務(wù)器啟動加載 AOF 文件時,發(fā)現(xiàn) AOF 文件被損壞了,那么服務(wù)器會拒絕加載這個 AOF 文件,以此來確保數(shù)據(jù)的一致性不被破壞。而 AOF 文件被損壞的原因可能是程序正在對 AOF 文件進(jìn)行寫入與同步時,服務(wù)器出現(xiàn)停機(jī)故障。如果 AOF 文件被損壞了,則可以通過以下方法來修復(fù)。

● 及時備份現(xiàn)有 AOF 文件。

● 利用 Redis 自帶的 redis-check-aof 程序,對原來的 AOF 文件進(jìn)行修復(fù),命令如下:

● 使用 diff-u 來對比原始 AOF 文件和修復(fù)后的 AOF 文件,找出這兩個文件的不同之處。

● 修復(fù) AOF 文件之后,重啟 Redis 服務(wù)器重新加載,進(jìn)行數(shù)據(jù)恢復(fù)。

AOF持久化的優(yōu)劣

● 使用 AOF 持久化會讓 Redis 持久化更長:通過設(shè)置不同的 fsync 策略來達(dá)到更長的持久化。具體有 3 種策略。

● 兼容性比較好:AOF 文件是一個日志文件,它的作用是記錄服務(wù)器執(zhí)行的所有寫命令。當(dāng)文件因?yàn)槟硹l寫命令寫入失敗時,可以使用 redis-check-aof 進(jìn)行修復(fù),然后繼續(xù)使用。

● 支持后臺重寫:當(dāng) AOF 文件的體積過大時,在后臺可以自動地對 AOF 文件進(jìn)行重寫,因此數(shù)據(jù)庫當(dāng)前狀態(tài)的所有命令集合都會被重寫到 AOF 文件中。重寫完成后,Redis 就會切換到新的 AOF 文件,繼續(xù)執(zhí)行寫命令的追加操作。

● AOF 文件易于讀取和加載:AOF 文件保存了對數(shù)據(jù)庫的所有寫命令,這些寫命令采用 Redis 協(xié)議格式追加到 AOF 文件中,因此非常容易讀取和加載。

AOF 持久化具有以下缺點(diǎn):

● AOF 文件的體積會隨著時間的推移逐漸變大,導(dǎo)致在加載時速度會比較慢,進(jìn)而影響數(shù)據(jù)庫狀態(tài)的恢復(fù)速度,性能快速下降。

● 根據(jù)所使用的 fsync 策略,使用 AOF 文件恢復(fù)數(shù)據(jù)的速度可能會慢于使用 RDB 文件恢復(fù)數(shù)據(jù)的速度。

● 因?yàn)?AOF 文件的個別命令,可能會導(dǎo)致在加載時失敗,從而無法進(jìn)行數(shù)據(jù)恢復(fù)。

RDB

RDB 持久化生成的 RDB 文件是一個經(jīng)過壓縮的二進(jìn)制文件,也可以稱之為快照文件,通過該文件可以還原生成 RDB 文件時的數(shù)據(jù)庫狀態(tài)

在指定的時間間隔內(nèi),Redis 會自動將內(nèi)存中的所有數(shù)據(jù)生成一份副本并存儲在硬盤上,這個過程就是「快照」。

快照怎么生成

● 根據(jù) Redis 配置文件 redis.conf 中的配置自動進(jìn)行快照

save 900 1
save 300 10
save 60 10000
save m n //時間 m 和被修改的鍵的個數(shù) n

當(dāng)在時間 m 內(nèi)被修改的鍵的個數(shù)大于 n 時,就會觸發(fā) BGSAVE 命令,服務(wù)器就會自動執(zhí)行快照操作。

Redis 的 save m n 命令是通過 serverCron 函數(shù)、dirty 計數(shù)器及 lastsave 時間戳來實(shí)現(xiàn)的。

serverCron 函數(shù):這是 Redis 服務(wù)器的周期性操作函數(shù),默認(rèn)每隔 100 毫秒執(zhí)行一次,它主要的作用是維護(hù)服務(wù)器的狀態(tài)。其中一項(xiàng)工作就是判斷 save m n 配置的條件是否滿足,如果滿足就會觸發(fā)執(zhí)行 BGSAVE 命令。

dirty 計數(shù)器:這是 Redis 服務(wù)器維持的一種狀態(tài),它主要用于記錄上一次執(zhí)行 SAVE 或 BGSAVE 命令后,服務(wù)器進(jìn)行了多少次狀態(tài)修改(執(zhí)行添加、刪除、修改等操作);當(dāng) SAVE 或 BGSAVE 命令執(zhí)行完成后,服務(wù)器會將 dirty 重新設(shè)置為 0。dirty 計數(shù)器記錄的是服務(wù)器進(jìn)行了多少次狀態(tài)修改,而不是客戶端執(zhí)行了多少次修改數(shù)據(jù)的命令。

lastsave 時間戳:主要用于記錄服務(wù)器上一次成功執(zhí)行 SAVE 或 BGSAVE 命令的時間,它是 Redis 服務(wù)器維持的一種狀態(tài)。

dirty 計數(shù)器和 lastsave 時間戳屬性都保存在服務(wù)器狀態(tài)的 redisServer 結(jié)構(gòu)中。

save m n 命令的實(shí)現(xiàn)原理:服務(wù)器每隔 100 毫秒執(zhí)行一次 serverCron 函數(shù);serverCron 函數(shù)會遍歷 save m n 配置的保存條件,判斷是否滿足。如果有一個條件滿足,就會觸發(fā)執(zhí)行 BGSAVE 命令,進(jìn)行快照保存。

對于每個 save m n 條件,只有以下兩個條件同時滿足才算滿足:

? 當(dāng)前服務(wù)器時間減去 lastsave 時間戳大于 m。

? 當(dāng)前 dirty 計數(shù)器的個數(shù)大于等于 n。

● 用戶在客戶端執(zhí)行 SAVE 或 BGSAVE 命令時會觸發(fā)快照(手動觸發(fā))。

● 如果用戶定義了自動快照條件,則執(zhí)行 FLUSHALL 命令也會觸發(fā)快照。

當(dāng)執(zhí)行 FLUSHALL 命令時,會清空數(shù)據(jù)庫中的所有數(shù)據(jù)。如果用戶定義了自動快照條件,則在使用 FLUSHALL 命令清空數(shù)據(jù)庫的過程中,就會觸發(fā)服務(wù)器執(zhí)行一次快照。

● 如果用戶為 Redis 設(shè)置了主從復(fù)制模式,從節(jié)點(diǎn)執(zhí)行全量復(fù)制操作,則主節(jié)點(diǎn)會執(zhí)行 BGSAVE 命令,將生產(chǎn)的 RDB 文件發(fā)送給從節(jié)點(diǎn)完成快照操作。

快照的實(shí)現(xiàn)過程

(1)Redis 調(diào)用執(zhí)行 fork 函數(shù)復(fù)制一份當(dāng)前進(jìn)程(父進(jìn)程)的副本(子進(jìn)程),也就是同時擁有父進(jìn)程和子進(jìn)程。

(2)父進(jìn)程與子進(jìn)程各自分工,父進(jìn)程繼續(xù)處理來自客戶端的命令請求,而子進(jìn)程則將內(nèi)存中的數(shù)據(jù)寫到硬盤上的一個臨時 RDB 文件中。

(3)當(dāng)子進(jìn)程把所有數(shù)據(jù)寫完后,也就表示快照生成完畢,此時舊的 RDB 文件將會被這個臨時 RDB 文件替換,這個舊的 RDB 文件也會被刪除。這個過程就是一次快照的實(shí)現(xiàn)過程。

當(dāng) Redis 調(diào)用執(zhí)行 fork 函數(shù)時,操作系統(tǒng)會使用寫時復(fù)制策略。也就是在執(zhí)行 fork 函數(shù)的過程中,父、子進(jìn)程共享同一內(nèi)存數(shù)據(jù),當(dāng)父進(jìn)程要修改某個數(shù)據(jù)時(執(zhí)行一條寫命令),操作系統(tǒng)會將這個共享內(nèi)存數(shù)據(jù)另外復(fù)制一份給子進(jìn)程使用,以此來保證子進(jìn)程的正確運(yùn)行。因此,新的 RDB 文件存儲的是執(zhí)行 fork 函數(shù)過程中的內(nèi)存數(shù)據(jù)。

寫時復(fù)制策略也保證了在執(zhí)行 fork 函數(shù)的過程中生成的兩份內(nèi)存副本在內(nèi)存中的占用量不會增加一倍。但是,在進(jìn)行快照的過程中,如果寫操作比較多,就會造成 fork 函數(shù)執(zhí)行前后數(shù)據(jù)差異較大,此時會使得內(nèi)存使用量變大。因?yàn)閮?nèi)存中不僅保存了當(dāng)前數(shù)據(jù)庫數(shù)據(jù),還會保存 fork 過程中的內(nèi)存數(shù)據(jù)。

在進(jìn)行快照生成的過程中,Redis 不會修改 RDB 文件。只有當(dāng)快照生成后,舊的 RDB 文件才會被臨時 RDB 文件替換,同時舊的 RDB 文件會被刪除。在整個過程中,RDB 文件是完整的,因此我們可以使用 RDB 文件來實(shí)現(xiàn) Redis 數(shù)據(jù)庫的備份。

RDB 文件

默認(rèn)情況下,Redis 將數(shù)據(jù)庫快照保存在名為 dump.rdb 的文件中。這個文件可以修改,即AOF的dir和dbfilename 屬性

RDB 文件結(jié)構(gòu):

img

在 RDB 文件結(jié)構(gòu)中,通常使用大寫字母表示常量,使用小寫字母表示變量和數(shù)據(jù)。

● REDIS 常量:該常量位于 RDB 文件的頭部,它保存著「REDIS」5 個字符,它的長度是 5 字節(jié)。在 Redis 服務(wù)器啟動加載文件時,程序會根據(jù)這 5 個字符判斷加載的文件是不是 RDB 文件。

● db_version 常量:該常量用于記錄 RDB 文件的版本號,它的值是一個用字符串表示的整數(shù),占 4 字節(jié),注意區(qū)分它不是 Redis 的版本號。

● databases 數(shù)據(jù):它包含 0 個或多個數(shù)據(jù)庫,以及各個數(shù)據(jù)庫中的鍵值對數(shù)據(jù)。

如果它包含 0 個數(shù)據(jù)庫,也就是服務(wù)器的數(shù)據(jù)庫狀態(tài)為空,那么 databases 也是空的,其長度為 0 字節(jié);如果它包含多個數(shù)據(jù)庫,也就是服務(wù)器的數(shù)據(jù)庫狀態(tài)不為空,那么 databases 不為空,根據(jù)它所保存的鍵值對的數(shù)量、類型和內(nèi)容不同,其長度也是不一樣的。

如果 databases 不為空,則 RDB 文件結(jié)構(gòu)如圖

img

其中,SELECTDB 是一個常量,表示其后的數(shù)據(jù)庫編號,這里的 0 和 1 是數(shù)據(jù)庫編號。

pairs 數(shù)據(jù):它存儲了具體的鍵值對信息,包括鍵(key)、值(value)、數(shù)據(jù)類型、內(nèi)部編碼、過期信息、壓縮信息等。

SELECT 0 pairs 表示 0 號數(shù)據(jù)庫;SELECT 1 pairs 表示 1 號數(shù)據(jù)庫。當(dāng)數(shù)據(jù)庫中有鍵值對時,RDB 文件才會記錄該數(shù)據(jù)庫的信息;而如果數(shù)據(jù)庫中沒有鍵值對,這一部分就會被 RDB 文件省略。

● EOF 常量:該常量是一個結(jié)束標(biāo)志,它標(biāo)志著 RDB 文件的正文內(nèi)容結(jié)束,其長度為 1 字節(jié)。在加載 RDB 文件時,如果遇到 EOF 常量,則表示數(shù)據(jù)庫中的所有鍵值對都已經(jīng)加載完畢。

● check_sum 變量:該變量用于保存一個校驗(yàn)和,這個校驗(yàn)和是通過對 REDIS、db_version、databases、EOF 4 部分的內(nèi)容進(jìn)行計算得出的,是一個無符號整數(shù),其長度為 8 字節(jié)。

當(dāng)服務(wù)器加載 RDB 文件時,會將 check_sum 變量中保存的校驗(yàn)和與加載數(shù)據(jù)時所計算出來的校驗(yàn)和進(jìn)行比對,從而判斷加載的 RDB 文件是否被損壞,或者是否有錯誤。

RDB文件壓縮

在默認(rèn)情況下,Redis 服務(wù)器會自動對 RDB 文件進(jìn)行壓縮。在 Redis 配置文件 redis.conf 中,默認(rèn)開啟壓縮。配置如下:

img

Redis 采用 LZF 算法進(jìn)行 RDB 文件壓縮。在壓縮 RDB 文件時,不要誤認(rèn)為是壓縮整個 RDB 文件。實(shí)際上,對 RDB 文件的壓縮只是針對數(shù)據(jù)庫中的字符串進(jìn)行的,并且只有當(dāng)字符串達(dá)到一定長度(20 字節(jié))時才會進(jìn)行壓縮。

RDB文件的創(chuàng)建

SAVE 命令: 會阻塞 Redis 服務(wù)器進(jìn)程,此時 Redis 服務(wù)器將不能繼續(xù)執(zhí)行其他命令請求,直到 RDB 文件創(chuàng)建完畢為止。

BGSAVE 命令: 會派生出一個子進(jìn)程,交由子進(jìn)程將內(nèi)存中的數(shù)據(jù)保存到硬盤中,創(chuàng)建 RDB 文件;而 BGSAVE 命令的父進(jìn)程可以繼續(xù)處理來自客戶端的命令請求。

執(zhí)行 BGSAVE 命令會返回 Background saving started 信息,但我們并不能確定 BGSAVE 命令是否已經(jīng)成功執(zhí)行,此時可以使用 LASTSAVE 命令來查看相關(guān)信息。

執(zhí)行 LASTSAVE 命令返回一個 UNIX 格式的時間戳,表示最近一次 Redis 成功將數(shù)據(jù)保存到硬盤中的時間。

RDB文件的加載

RDB 文件只有在啟動服務(wù)器的時候才會被加載。當(dāng)啟動服務(wù)器時,它會檢查 RDB 文件是否存在,如果存在,就會自動加載 RDB 文件。除此之外,RDB 文件不會被加載,因?yàn)?Redis 中沒有提供用于加載 RDB 文件的命令。

那么先加載AOF文件還是RDB文件呢?

● 如果在 Redis 配置文件中開啟了 AOF 持久化(appendonly yes),那么在啟動服務(wù)器的時候會優(yōu)先加載 AOF 文件來還原數(shù)據(jù)庫狀態(tài)。

● 如果在 Redis 配置文件中關(guān)閉了 AOF 持久化(appendonly no),那么在啟動服務(wù)器的時候會優(yōu)先加載 RDB 文件來還原數(shù)據(jù)庫狀態(tài)。

RDB文件的配置

除了save m n、 dbfilename dump.rdb、 dir./ 還有

● stop-writes-on-bgsave-error yes:當(dāng)執(zhí)行 BGSAVE 命令出現(xiàn)錯誤時,Redis 是否終止執(zhí)行寫命令。參數(shù)的值默認(rèn)被設(shè)置為 yes,表示當(dāng)硬盤出現(xiàn)問題時,服務(wù)器可以及時發(fā)現(xiàn),及時避免大量數(shù)據(jù)丟失;當(dāng)設(shè)置為 no 時,就算執(zhí)行 BGSAVE 命令發(fā)生錯誤,服務(wù)器也會繼續(xù)執(zhí)行寫命令;當(dāng)對 Redis 服務(wù)器的系統(tǒng)設(shè)置了監(jiān)控時,建議將該參數(shù)值設(shè)置為 no。

● rdbcompression yes:是否開啟 RDB 壓縮文件,默認(rèn)為 yes 表示開啟,不開啟則設(shè)置為 no。

● rdbchecksum yes:是否開啟 RDB 文件的校驗(yàn),在服務(wù)器進(jìn)行 RDB 文件的寫入與讀取時會用到它。默認(rèn)設(shè)置為 yes。如果將它設(shè)置為 no,則在服務(wù)器對 RDB 文件進(jìn)行寫入與讀取時,可以提升性能,但是無法確定 RDB 文件是否已經(jīng)被損壞。

RDB 持久化的優(yōu)劣

● RDB 文件是一個經(jīng)過壓縮的二進(jìn)制文件,文件緊湊,體積較小,非常適用于進(jìn)行數(shù)據(jù)庫數(shù)據(jù)備份。

● RDB 持久化適用于災(zāi)難恢復(fù),而且恢復(fù)數(shù)據(jù)時的速度要快于 AOF 持久化。

● Redis 采用 RDB 持久化可以很大程度地提升性能。父進(jìn)程在保存 RDB 文件時會啟動一個子進(jìn)程,將所有與保存相關(guān)的功能交由子進(jìn)程處理,而父進(jìn)程可以繼續(xù)處理其他相關(guān)的操作。

RDB 持久化具有以下缺點(diǎn):

● 在服務(wù)器出現(xiàn)故障時,如果沒有觸發(fā) RDB 快照執(zhí)行,那么它可能會丟失大量數(shù)據(jù)。RDB 快照的持久化方式?jīng)Q定了必然做不到實(shí)時持久化,會存在大量數(shù)據(jù)丟失。

● 當(dāng)數(shù)據(jù)量非常龐大時,在保存 RDB 文件的時候,服務(wù)器會啟動一個子進(jìn)程來完成相關(guān)的保存操作。這項(xiàng)操作比較耗時,將會占用太多 CPU 時間,從而影響服務(wù)器的性能。

● RDB 文件存在兼容性問題,老版本的 Redis 不支持新版本的 RDB 文件。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容