為什么斷電后Redis數(shù)據(jù)不會(huì)丟失
前言
Redis 作為一款內(nèi)存數(shù)據(jù)庫,被廣泛使用于緩存,分布式鎖等場景,那么假如斷電或者因其他因素導(dǎo)致 Reids 服務(wù)宕機(jī),在重啟之后數(shù)據(jù)會(huì)丟失嗎?
Redis 持久化機(jī)制
Redis 雖然是定義為一個(gè)內(nèi)存數(shù)據(jù)庫,但是其也支持?jǐn)?shù)據(jù)的持久化,在 Redis 中提供了兩種持久化機(jī)制:RDB 持久化和 AOF 持久化。
RDB 持久化機(jī)制
RDB 全稱為:Redis DataBase,是 Redis 當(dāng)中默認(rèn)的持久化方案。當(dāng)觸發(fā)持久化條件時(shí),Redis 默認(rèn)會(huì)生成一個(gè) dump.rdb 文件,Redis 在重啟的時(shí)候就會(huì)通過解析 dump.rdb 文件進(jìn)行數(shù)據(jù)恢復(fù)。
RDB 機(jī)制觸發(fā)條件
RDB 持久化機(jī)制有兩種觸發(fā)方式:自動(dòng)觸發(fā)和手動(dòng)觸發(fā)。
自動(dòng)觸發(fā)
自動(dòng)觸發(fā)方式也可以分為三種:
- 執(zhí)行
flushall命令(flushdb命令不會(huì)觸發(fā))時(shí),不過此時(shí)生成的dump文件內(nèi)的數(shù)據(jù)是空的(dump文件還會(huì)存儲(chǔ)一些頭信息,所以文件本身是有內(nèi)容的,只是沒有數(shù)據(jù)),沒有什么太大的實(shí)際意義。 - 執(zhí)行
shutdown命令時(shí)會(huì)觸發(fā)生成dump文件。 - 通過配置文件自動(dòng)生成,
Redis中配置文件默認(rèn)配置如下,只要達(dá)到這三個(gè)條件中的任意一個(gè),就會(huì)觸發(fā)Redis的RDB持久化機(jī)制。
save 900 1 //900秒內(nèi)至少有1個(gè)key被添加或者更新 save 300 10 //300秒內(nèi)至少有10個(gè)key被添加或者更新 save 60 10000 //60秒內(nèi)至少有10000個(gè)key被添加或者更新
手動(dòng)觸發(fā)
除了自動(dòng)觸發(fā),Redis 中還提供了 2 個(gè)手動(dòng)觸發(fā) RDB 機(jī)制的命令(這兩個(gè)命令不能同時(shí)被執(zhí)行,一旦一個(gè)命令正在執(zhí)行中,另一個(gè)命令會(huì)被拒絕執(zhí)行):
save:這個(gè)命令會(huì)阻塞Redis服務(wù)器進(jìn)程,直到成功創(chuàng)建RDB文件,也就是說在生成RDB文件之前,服務(wù)器不能處理客戶端發(fā)送的任何命令。bgsave:父進(jìn)程會(huì)執(zhí)行fork操作來創(chuàng)建一個(gè)子進(jìn)程。RDB文件由子進(jìn)程來負(fù)責(zé)生成,父進(jìn)程可以正常處理客戶端發(fā)送的命令(這里也是Redis不僅僅只是單線程的一個(gè)體現(xiàn))。
如果想要知道上一次成功執(zhí)行 save 或者 bgsave 命令的時(shí)間,可以執(zhí)行 lastsave 命令進(jìn)行查看,lastsave 命令返回的是一個(gè) unix 時(shí)間戳。
RDB 機(jī)制相關(guān)配置文件
除了上面提到的觸發(fā)生成 rdb 文件的配置參數(shù),RDB 持久化機(jī)制還有如下一些相關(guān)命令:
dir:rdb 文件生成目錄。默認(rèn)是 ./(當(dāng)前目錄),可以執(zhí)行命令 config get dir 進(jìn)行查看,如下圖所示說明當(dāng)前 dump 文件生成目錄為 /usr/local/redis-5.0.5/bin:

dbfilename:rdb 文件名。默認(rèn)是 dump.rdb。
rdbcompression:rdb 文件是否是 LZF 壓縮文件。默認(rèn)是 yes。
rdbchecksum:是否開啟數(shù)據(jù)校驗(yàn)。默認(rèn)是 yes。
RDB 機(jī)制優(yōu)點(diǎn)
RDB是一個(gè)非常緊湊的壓縮文件,保存了不同時(shí)間點(diǎn)上的文件,非常適合用來災(zāi)備和數(shù)據(jù)恢復(fù)。RDB最大限度地提高了Redis的性能,因?yàn)?Redis父進(jìn)程需要做的唯一的工作就是派生一個(gè)子進(jìn)程來完成剩下的工作,父進(jìn)程永遠(yuǎn)不會(huì)執(zhí)行磁盤I/O或類似的耗時(shí)操作。- 與后面介紹的
AOF持久化機(jī)制比較,RDB方式恢復(fù)數(shù)據(jù)的速度更快。
RDB 機(jī)制缺點(diǎn)
RDB無法做到實(shí)時(shí)備份,所以如果Redis因異常停止工作而沒有正確的關(guān)機(jī),那么從上一次備份的到異常宕機(jī)的這一段時(shí)間的數(shù)據(jù)將會(huì)丟失。RDB通常需要父進(jìn)程來執(zhí)行fork操作創(chuàng)建子線程,所以如果頻繁執(zhí)行fork操作而CPU性能又不是很高的話可能會(huì)造成短時(shí)間內(nèi)父進(jìn)程不可用。
AOF 持久化機(jī)制
AOF 全稱為:Append Only File,是 Redis 當(dāng)中提供的另一種持久化機(jī)制。AOF 采用日志的形式將每個(gè)寫操作追加到文件中。開啟 AOF 機(jī)制后,只要執(zhí)行更改 Redis 數(shù)據(jù)的命令時(shí),命令就會(huì)被寫入到 AOF 文件中。在 Redis 重啟的時(shí)候會(huì)根據(jù)日志內(nèi)容依次執(zhí)行 AOF 文件中的命令來恢復(fù)數(shù)據(jù)。
AOF 和 RDB 最大的不同是:AOF 記錄的是執(zhí)行命令(類似于 MySQL 中 binlog 的 statement 格式),而RDB 記錄的是數(shù)據(jù)(類似于 MySQL 中 binlog 的 row 格式)。
需要注意的是:假如同時(shí)開啟了 RDB 和 AOF 兩種機(jī)制,那么 Redis 會(huì)優(yōu)先選擇 AOF 持久化文件來進(jìn)行數(shù)據(jù)恢復(fù)。
AOF 機(jī)制如何開啟
AOF 機(jī)制默認(rèn)是關(guān)閉的,可以通過以下配置文件進(jìn)行修改
appendonly no //是否開啟AOF機(jī)制,默認(rèn)是no表示關(guān)閉,修改為yes則表示開啟 appendfilename "appendonly.aof" //AOF文件名
PS:和 RDB 機(jī)制一樣,其生成文件的路徑也是通過 dir 屬性進(jìn)行配置。
AOF 機(jī)制數(shù)據(jù)是否實(shí)時(shí)寫入磁盤
AOF 機(jī)制下數(shù)據(jù)是否實(shí)時(shí)寫入磁盤,這個(gè)和 MySQL 的 redo log 機(jī)制很類似,也是需要通過參數(shù)來進(jìn)行控制。
AOF 數(shù)據(jù)何時(shí)寫入磁盤由參數(shù) appendfsync 來進(jìn)行控制:
| appendfsync | 描述 | 備注 |
|---|---|---|
| always | 寫入緩存的同時(shí)通知操作系統(tǒng)刷新(fsync)到磁盤(但是也可能會(huì)有部分操作系統(tǒng)只是盡快刷盤,而不是實(shí)時(shí)刷盤) | Slow, Safest |
| everysec | 先寫入緩存,然后每秒中刷一次盤(默認(rèn)值),這種模式極端情況可能會(huì)丟失 1s 的數(shù)據(jù) | Compromise |
| no | 只寫入緩存,什么時(shí)候刷盤由操作系統(tǒng)自己決定 | Faster |
AOF 文件重寫
AOF 機(jī)制主要是通過記錄執(zhí)行命令的方式來實(shí)現(xiàn)的,那么隨著時(shí)間的增加,AOF 文件不可避免的會(huì)越來越大,而且可能會(huì)出現(xiàn)很多冗余命令。比如同一個(gè) key 值執(zhí)行了 10000 次 set 操作,實(shí)際上前面 9999 次對恢復(fù)數(shù)據(jù)來說都是沒用的,只需要執(zhí)行最后一次命令就可以把數(shù)據(jù)恢復(fù),正是為了避免這種問題,AOF 機(jī)制就提供了文件重寫功能。
重寫原理分析
AOF 重寫時(shí) Redis 并不會(huì)去分析原有的文件,因?yàn)槿绻形募^大,分析也會(huì)很耗時(shí),所以 Redis 選擇的做法就是重新去 Redis 中讀取現(xiàn)有的鍵值對,然后用一條命令記錄鍵值對的值。
只使用一條命令也有一個(gè)前提,那就是一個(gè)集合鍵或者列表鍵或者哈希鍵內(nèi)包含的元素不能超過 64 個(gè),一旦超過 64 個(gè),就會(huì)使用多條命令來進(jìn)行記錄。
AOF 重寫緩沖區(qū)
AOF 重寫的時(shí)候一般都會(huì)有大量的寫操作,所以為了不阻塞客戶端的命令請求,Redis 會(huì)把重寫操作放入到子進(jìn)程中執(zhí)行,但是放入子進(jìn)程中執(zhí)行也會(huì)帶來一個(gè)問題,那就是重寫期間如果同時(shí)又執(zhí)行了客戶端發(fā)過來的命令,又該如何保證數(shù)據(jù)的一致性?
為了解決數(shù)據(jù)不一致問題,Redis 中引入了一個(gè) AOF 重寫緩沖區(qū)。當(dāng)開始執(zhí)行 AOF 文件重寫之后又接收到客戶端的請求命令,不但要將命令寫入原本的 AOF 緩沖區(qū)(根據(jù)上面提到的參數(shù)刷盤),還要同時(shí)寫 入 AOF 重寫緩沖區(qū):

一旦子進(jìn)程完成了 AOF 文件的重寫,此時(shí)會(huì)向父進(jìn)程發(fā)出信號,父進(jìn)程收到信號之后會(huì)進(jìn)行阻塞(阻塞期間不執(zhí)行任何命令),并進(jìn)行以下兩項(xiàng)工作:
- 將
AOF重寫緩沖區(qū)的文件刷新到新的AOF文件內(nèi)。 - 將新
AOF文件進(jìn)行改名并原子的替換掉舊的AOF文件。
完成了上面的兩項(xiàng)工作之后,整個(gè) AOF 重寫工作完成,父進(jìn)程開始正常接收命令。
AOF 機(jī)制觸發(fā)條件
AOF 機(jī)制的觸發(fā)條件同樣也分為自動(dòng)觸發(fā)和手動(dòng)觸發(fā)。
自動(dòng)觸發(fā):自動(dòng)觸發(fā)可以通過以下參數(shù)進(jìn)行設(shè)置:
auto-aof-rewrite-percentag //文件大小超過上次AOF重寫之后的文件的百分比。默認(rèn)100,也就是默認(rèn)達(dá)到上一次AOF重寫文件的2倍之后會(huì)再次觸發(fā)AOF重寫 auto-aof-rewrite-min-size //設(shè)置允許重寫的最小AOF文件大小,默認(rèn)是64M。主要是避免滿足了上面的百分比,但是文件還是很小的情況。
手動(dòng)觸發(fā):執(zhí)行 bgrewriteaof 命令。
注意:bgrewriteaof 命令也不能和上面 RDB 持久化命令 bgsave 同時(shí)執(zhí)行,這么做是為了避免同時(shí)創(chuàng)建兩個(gè)子進(jìn)程來同時(shí)執(zhí)行大量寫磁盤操作,影響到 Redis 的性能。
AOF 機(jī)制機(jī)制優(yōu)點(diǎn)
- 使用
AOF機(jī)制,可以自由選擇不同fsync(刷盤)策略,而且在默認(rèn)策略下最多也僅僅是損失1s的數(shù)據(jù)。 AOF日志是一個(gè)僅追加的日志,因此如果出現(xiàn)斷電,也不存在查找或損壞問題。即使由于某些原因(磁盤已滿或其他原因),日志已經(jīng)寫了一半的命令結(jié)束,redis-check-aof工具也能夠輕松地修復(fù)它。- 當(dāng)
AOF文件變得太大時(shí),Redis能夠在后臺(tái)自動(dòng)重寫。 - 不同于
RDB的文件格式,AOF是一種易于理解和解析的格式,依次包含所有操作的日志。
AOF 機(jī)制機(jī)制缺點(diǎn)
- 對于相同的數(shù)據(jù)集,
AOF文件通常比等效的RDB文件大。 - 根據(jù)
fsync的具體策略,AOF機(jī)制可能比RDB機(jī)制慢。但是一般情況下,fsync設(shè)置為每秒的性能仍然很高,禁用fsync后,即使在高負(fù)載下,它的速度也能和RDB一樣快。 - 因?yàn)?
AOF文件是追加形式,可能會(huì)遇到BRPOP、LPUSH等阻塞命令的錯(cuò)誤,從而導(dǎo)致生成的AOF在重新加載時(shí)不能復(fù)制完全相同的數(shù)據(jù)集,而RDB文件每次都是重新從頭創(chuàng)建快照,這在一定程度上來說RDB文件更加健壯。
總結(jié)
本文主要介紹了 Redis 的兩種持久化機(jī)制:RDB 和 AOF,并分別介紹了兩種持久化機(jī)制的原理,通過對兩種持久化機(jī)制的對比分析了兩種持久化機(jī)制各自的優(yōu)點(diǎn)和缺點(diǎn)。
到此這篇關(guān)于為什么斷電后Redis數(shù)據(jù)不會(huì)丟失的文章就介紹到這了,更多相關(guān)Redis數(shù)據(jù)丟失內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Redis之常用數(shù)據(jù)結(jié)構(gòu)哈希表
這篇文章主要介紹了Redis常用的數(shù)據(jù)結(jié)構(gòu)哈希表,哈希表是一種保存鍵值對的數(shù)據(jù)結(jié)構(gòu),具有一定的參考價(jià)值,需要的朋友可以參考閱讀2023-04-04
Redis bitmap 實(shí)現(xiàn)簽到案例(最新推薦)
這篇文章主要介紹了Redis bitmap 實(shí)現(xiàn)簽到案例,通過設(shè)計(jì)簽到功能對應(yīng)的數(shù)據(jù)庫表,結(jié)合sql語句給大家講解的非常詳細(xì),具體示例代碼跟隨小編一起看看吧2024-07-07
用Redis實(shí)現(xiàn)微博關(guān)注關(guān)系
在微博中,每一個(gè)用戶都會(huì)有一個(gè)關(guān)注列表,一個(gè)粉絲列表。用戶可以查看自己的關(guān)注,粉絲列表,也可以查看別人的關(guān)注,粉絲列表。并且,要展示列表里每個(gè)人與當(dāng)前查看者的關(guān)注狀態(tài)。2015-09-09
通俗易懂的Redis數(shù)據(jù)結(jié)構(gòu)基礎(chǔ)教程(入門)
這篇文章主要介紹了通俗易懂的Redis數(shù)據(jù)結(jié)構(gòu)基礎(chǔ)教程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
redis中opsForList().range()的使用方法詳解
這篇文章主要給大家介紹了關(guān)于redis中opsForList().range()的使用方法,文中通過實(shí)例代碼以及圖文介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-03-03

