Redis 的持久化與過期鍵

簡(jiǎn)介

Redis 是使用非常廣泛的 Key-Value 內(nèi)存數(shù)據(jù)庫(kù)。因?yàn)閿?shù)據(jù)都存放在內(nèi)存中,所以存取速度非常快。不過,很多情況下我們需要將 Redis 中的數(shù)據(jù)保存到硬盤中以便做備份。Redis 提供了兩種數(shù)據(jù)持久化方式,分別是 RDB 和 AOP,本文分析這兩種方式的使用以及過期鍵對(duì)持久化的影響。

RDB

RDB 指的是將 Redis 數(shù)據(jù)庫(kù)在某個(gè)時(shí)間點(diǎn)的快照保存到磁盤,所生成的 RDB 文件是一個(gè)經(jīng)過壓縮的二進(jìn)制文件,通過這個(gè)文件可以還原出 Redis 的數(shù)據(jù)狀態(tài)。

創(chuàng)建快照的方式有以下幾種:

  • 客戶端向 Redis 發(fā)送 BGSAVE 命令,Redis 會(huì)調(diào)用 fork 創(chuàng)建一個(gè)子進(jìn)程,然后子進(jìn)程負(fù)責(zé)將快照寫入硬盤,而父進(jìn)程繼續(xù)處理命令請(qǐng)求。
  • 客戶端向 Redis 發(fā)送 SAVE 命令,此時(shí) Redis 將開始創(chuàng)建快照,并且在完成之前不再響應(yīng)其它命令。
  • 用戶設(shè)置 save 配置選項(xiàng),比如 save 60 10000,那么從 Redis 最近一次創(chuàng)建快照算起,當(dāng) “60 秒內(nèi)有 10000 次寫入” 這個(gè)條件被滿足時(shí), Redis 就會(huì)自動(dòng)觸發(fā) BGSAVE 命令。如果用戶設(shè)置了多個(gè) save 配置選項(xiàng),那么當(dāng)任意一個(gè) save 配置滿足時(shí),Redis 就會(huì)觸發(fā)一次 BGSAVE 命令。save 配置的格式如下所示:
save 60 10000
stop-writes-on-bgsave-error no
rdbcompression yes    // 使用壓縮
dbfilename dump.rdb  // RBD 文件的名字

dir ./
  • 當(dāng) Redis 通過 SHUTDOWN 命令接收到關(guān)閉服務(wù)器的請(qǐng)求時(shí),或者接收到 TERM命令時(shí),會(huì)執(zhí)行一個(gè) SAVE 命令,并且阻塞所有的客戶端,不再執(zhí)行任何請(qǐng)求。在 SAVE 命令執(zhí)行結(jié)束后關(guān)閉服務(wù)器。

  • 當(dāng)一個(gè) Redis 服務(wù)器連接另一個(gè) Redis 服務(wù)器,并向?qū)Ψ桨l(fā)送 SYNC 命令來開始一次復(fù)制操作的時(shí)候,如果主服務(wù)器沒有在執(zhí)行 BGSAVE 操作,或者主服務(wù)器并非剛執(zhí)行完 BGSAVE,那么主服務(wù)器會(huì)執(zhí)行 BGSAVE 命令。

RDB 的主要問題是,如果系統(tǒng)發(fā)生崩潰,那么最近一次執(zhí)行完快照后修改的數(shù)據(jù)將被丟失。因此,RDB 適合用于即使丟失一部分?jǐn)?shù)據(jù)也不會(huì)造成影響的應(yīng)用程序。

AOF

AOF 指的是將所有執(zhí)行的寫命令寫到 AOF 文件的末尾,以此來記錄數(shù)據(jù)發(fā)生的變化。如果 Redis 想要恢復(fù) AOF 中的數(shù)據(jù),只要重新執(zhí)行一次 AOF 文件中所包含的寫命令就可以。

AOF 的配置如下所示:

appendonly yes  // 打開 aof
appendfsync everysec // aof 同步的頻率
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100 // 文件大小增長(zhǎng)比超過這個(gè)值開始自動(dòng)重寫 aof
auto-aof-rewrite-min-size 64mb  // 文件大小超過這個(gè)值才可以有可能自動(dòng)重寫 aof

上面的配置中,appendfsync everysec 設(shè)置的是同步的頻率。應(yīng)用程序在向硬盤寫入數(shù)據(jù)的時(shí)候有 3 個(gè)步驟:

  1. 調(diào)用 file.write() 向文件寫入,此時(shí)需要寫入的內(nèi)容被存儲(chǔ)到了緩沖區(qū),并不是真正寫到硬盤上了。
  2. 操作系統(tǒng)在某個(gè)時(shí)候?qū)⒕彌_區(qū)的內(nèi)容寫入硬盤,這時(shí)數(shù)據(jù)才真正被持久化了。

操作系統(tǒng)使用以上的文件寫入方式是為了提高性能,畢竟硬盤 I/O 操作是比較耗時(shí)的。但是,這種方式的缺點(diǎn)在于如果機(jī)器崩潰了那么緩沖區(qū)的內(nèi)容將丟失。程序可以使用 file.flush() 來請(qǐng)求操作系統(tǒng)盡快地將緩沖區(qū)的內(nèi)容刷新到硬盤上,不過何時(shí)開始執(zhí)行仍然由操作系統(tǒng)決定。程序也可以命令操作系統(tǒng)將文件同步 ( sync ) 到硬盤,同步操作會(huì)阻塞應(yīng)用程序直到數(shù)據(jù)被寫入硬盤。當(dāng)同步操作完成后,即使系統(tǒng)出現(xiàn)故障,也不會(huì)對(duì)被同步的文件造成影響。

對(duì)于 Redis 來講,可以指定 appendfsync 以何種方式讓數(shù)據(jù)完全同步到硬盤,這個(gè)配置有 3 個(gè)選項(xiàng):

  1. always: 每個(gè) Redis 寫命令都立即同步到硬盤,這是比較消耗性能的
  2. everysec: 每秒執(zhí)行一次同步,兼顧性能與數(shù)據(jù)安全,是比較常用的選項(xiàng)
  3. no: 讓操作系統(tǒng)決定何時(shí)進(jìn)行同步

always 可以使得在 Redis 發(fā)生崩潰時(shí)丟失的數(shù)據(jù)最少,但是也是最消耗性能的,導(dǎo)致 Redis 的處理速度變慢。ererysec 是一種兼顧性能與數(shù)據(jù)安全的方式,在這種情況下,如果系統(tǒng)崩潰,用戶最多會(huì)丟失一秒內(nèi)的數(shù)據(jù)。no 選項(xiàng)完全將同步交給操作系統(tǒng)被決定,性能也不比 everysec 高多少,是不推薦的方式。

AOF 的缺點(diǎn)是隨著 Redis 的不斷運(yùn)行,AOF 文件可能會(huì)非常大,甚至用完硬盤的空間。解決這個(gè)問題的辦法是 AOF 重寫。

重寫

客戶端可以發(fā)送 BGREWRITEAOF 命令讓 Redis 重寫 AOF 文件,Redis 會(huì)移除冗余的 AOF 命令進(jìn)行重寫,使得 AOF 文件的體積盡可能地小。

除了客戶端主動(dòng)發(fā)送 BGREWRITEAOF 命令,也可以使用配置讓 Redis 在滿足一定條件地情況下自動(dòng)開始重寫 AOF 文件。例如上一小節(jié)設(shè)置了 auto-aof-rewrite-percentage 100auto-aof-rewrite-min-size 64mb。這兩個(gè)配置的含義是,如果 AOF 文件大于 64MB 并且比上一次重寫之后的大小增加了一倍的時(shí)候,Redis 將執(zhí)行 BGREWERITEAOF 命令。

過期鍵刪除

用戶往往為 Redis 中的鍵設(shè)定過期時(shí)間,因此需要一定的策略來刪除過期鍵,可以有三種策略:

  1. 定時(shí)刪除,即通過定時(shí)器在過期時(shí)間到達(dá)的時(shí)候刪除過期的鍵。這種方式的優(yōu)點(diǎn)是節(jié)省內(nèi)存,不會(huì)因?yàn)榇罅康倪^期鍵占用內(nèi)存資源,而缺點(diǎn)則是消耗 CPU 資源,尤其是過期鍵數(shù)量較多的時(shí)候,刪除操作消耗太長(zhǎng)時(shí)間,降低了 Redis 的響應(yīng)時(shí)間。

  2. 惰性刪除,即在每次獲取某個(gè)鍵的時(shí)候判斷是否過期,如果未過期,則正常返回其值,否則刪除這個(gè)鍵,返回空。這種方式的優(yōu)點(diǎn)是節(jié)省 CPU 資源,但是消耗了內(nèi)存。尤其是過期鍵數(shù)量較多的時(shí)候,大量?jī)?nèi)存被無效的鍵占用,相當(dāng)于內(nèi)存泄露。

  3. 定期刪除,即每隔一段時(shí)間周期對(duì)數(shù)據(jù)庫(kù)中的鍵進(jìn)行掃描,但是只掃描其中一部分,力求在內(nèi)存和 CPU 之間達(dá)到一個(gè)平衡。

從上面 3 種策略可以看出,單用第一個(gè)肯定是不行的,Redis 的響應(yīng)時(shí)間至關(guān)重要。第二個(gè)則是比較好的方式,在獲取鍵的時(shí)候判斷是否過期并決定是否刪除,它的缺點(diǎn)是很多鍵無法及時(shí)刪除。如果一個(gè)過期鍵再也沒有被訪問,那么它將永遠(yuǎn)留在內(nèi)存中,而第三種方式正好可以彌補(bǔ)。

Redis 中過期鍵的刪除策略正是惰性刪除與定期刪除的結(jié)合。

過期鍵與持久化

了解了過期鍵的刪除策略后,下面看下鍵的過期時(shí)間對(duì)持久化的影響。

在生成 RDB 文件的過程中,如果一個(gè)鍵已經(jīng)過期,那么其不會(huì)被保存到 RDB 文件中。在載入 RDB 的時(shí)候,要分兩種情況:

  1. 如果 Redis 以主服務(wù)器的模式運(yùn)行,那么會(huì)對(duì) RDB 中的鍵進(jìn)行時(shí)間檢查,過期的鍵不會(huì)被恢復(fù)到 Redis 中。
  2. 如果 Redis 以從服務(wù)器的模式運(yùn)行,那么 RDB 中所有的鍵都會(huì)被載入,忽略時(shí)間檢查。在從服務(wù)器與主服務(wù)器進(jìn)行數(shù)據(jù)同步的時(shí)候,從服務(wù)器的數(shù)據(jù)會(huì)先被清空,所以載入過期鍵不會(huì)有問題。

對(duì)于 AOF 來說,如果一個(gè)鍵過期了,那么不會(huì)立刻對(duì) AOF 文件造成影響。因?yàn)?Redis 使用的是惰性刪除和定期刪除,只有這個(gè)鍵被刪除了,才會(huì)往 AOF 文件中追加一條 DEL 命令。在重寫 AOF 的過程中,程序會(huì)檢查數(shù)據(jù)庫(kù)中的鍵,已經(jīng)過期的鍵不會(huì)被保存到 AOF 文件中。

在運(yùn)行過程中,對(duì)于主從復(fù)制的 Redis,主服務(wù)器和從服務(wù)器對(duì)于過期鍵的處理也不相同:

  1. 對(duì)于主服務(wù)器,一個(gè)過期的鍵被刪除了后,會(huì)向從服務(wù)器發(fā)送 DEL 命令,通知從服務(wù)器刪除對(duì)應(yīng)的鍵
  2. 從服務(wù)器接收到讀取一個(gè)鍵的命令時(shí),即使這個(gè)鍵已經(jīng)過期,也不會(huì)刪除,而是照常處理這個(gè)命令。
  3. 從服務(wù)器接收到主服務(wù)器的 DEL 命令后,才會(huì)刪除對(duì)應(yīng)的過期鍵。

這么做的主要目的是保證數(shù)據(jù)一致性,所以當(dāng)一個(gè)過期鍵存在于主服務(wù)器時(shí),也必然存在于從服務(wù)器。

總結(jié)

本文對(duì) Redis 的兩種持久化方式進(jìn)行了簡(jiǎn)要的梳理,分析了 Redis 刪除過期鍵的策略以及對(duì)持久化的影響。理解了這部分內(nèi)容不僅可以讓我們對(duì) Redis 的使用更加得心應(yīng)手,對(duì)于學(xué)習(xí) Redis 的其它內(nèi)容如復(fù)制的過程也會(huì)很有幫助。

參考

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

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

  • 從這篇文章開始,將依次介紹Redis高可用相關(guān)的知識(shí)——持久化、復(fù)制(及讀寫分離)、哨兵、以及集群。 本文將先說明...
    不變甄心閱讀 737評(píng)論 0 4
  • 前言 在上一篇文章中,介紹了Redis內(nèi)存模型,從這篇文章開始,將依次介紹Redis高可用相關(guān)的知識(shí)——持久化、復(fù)...
    Java架構(gòu)閱讀 2,503評(píng)論 3 21
  • 一、Redis高可用概述 在介紹Redis高可用之前,先說明一下在Redis的語(yǔ)境中高可用的含義。 我們知道,在w...
    空語(yǔ)閱讀 1,681評(píng)論 0 2
  • 企業(yè)級(jí)redis集群架構(gòu)的特點(diǎn) 海量數(shù)據(jù) 高并發(fā) 高可用 要達(dá)到高可用,持久化是不可減少的,持久化主要是做災(zāi)難恢復(fù)...
    lucode閱讀 2,283評(píng)論 0 7
  • 在布局文件中給edittext的父控件增加兩個(gè)屬性
    柏林billy閱讀 1,657評(píng)論 0 1

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