Redis持久化AOF示例詳解
基礎(chǔ)面試題
什么是AOF
AOF(Append-Only File)
用于將Redis服務(wù)器收到的寫(xiě)操作追加到日志文件,通過(guò)該機(jī)制可以保證服務(wù)器重啟后依然可以依靠日志文件恢復(fù)數(shù)據(jù)。
它的工作過(guò)程大抵分為以下幾步:
- 收到客戶端的寫(xiě)入命令(例如SET、DEL等)之后,它會(huì)將命令寫(xiě)入AOF緩沖區(qū)。
- redis服務(wù)器會(huì)定期或者在特定條件下,將AOF緩沖區(qū)的數(shù)據(jù)以追加的方式寫(xiě)到日志文件末尾,這種寫(xiě)入的操作可以是同步的,也可以是異步的,具體看我們配置的刷盤(pán)機(jī)制。
- 若日志文件超過(guò)配置文件的大小(由配置參數(shù) auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size 決定),則會(huì)觸發(fā)AOF重寫(xiě)(AOF Rewrite),重寫(xiě)時(shí)會(huì)啟動(dòng)一個(gè)后臺(tái)進(jìn)程,分析日志中的指令并精簡(jiǎn)化寫(xiě)入新的AOF文件中。
- 新的AOF文件和舊的AOF文件進(jìn)行原子替換,后續(xù)的寫(xiě)指令都會(huì)寫(xiě)到這個(gè)新的AOF文件中。
AOF寫(xiě)后記錄日志有哪些優(yōu)劣
有如下幾個(gè)優(yōu)勢(shì):
- 客戶端操作的指令可能會(huì)出錯(cuò),采用寫(xiě)后再日志的形式可以避免很多沒(méi)必要的日志記錄,節(jié)約磁盤(pán)空間
- 寫(xiě)日志需要進(jìn)行磁盤(pán)IO,可能會(huì)產(chǎn)生阻塞,所以采用先寫(xiě)入再日志,可以避免寫(xiě)時(shí)阻塞。
當(dāng)然劣勢(shì)也很明顯:
- 有可能在寫(xiě)操作之后,日志記錄之前服務(wù)器出現(xiàn)宕機(jī),可能會(huì)造成數(shù)據(jù)丟失
- 當(dāng)主線程磁盤(pán)壓力過(guò)大,導(dǎo)致寫(xiě)入磁盤(pán)慢,進(jìn)而造成后續(xù)操作阻塞。
AOF核心配置參數(shù)有哪些
- appendonly :若將該參數(shù)設(shè)置為
yes
,則開(kāi)啟aof
持久化機(jī)制,此時(shí)redis
持久化機(jī)制就以aof
為主,而非rdb
# 設(shè)置為yes開(kāi)啟aof appendonly yes
如下示例所示,我們將該參數(shù)配置為yes
后重啟redis
服務(wù)端,使用客戶端完成如下操作
# 設(shè)置三個(gè)key 127.0.0.1:6379> set k1 v1 OK 127.0.0.1:6379> set k2 v2 OK 127.0.0.1:6379> set k3 v3 OK 127.0.0.1:6379>
此時(shí)我們查看aof文件,大小增加了
[root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# find / -name appendonly.aof /usr/sbin/appendonly.aof [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# find / -name appendonly [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# find / -name appendonly.aof /usr/sbin/appendonly.aof [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# ll appendonly.aof -rw-r--r-- 1 root root 110 Aug 26 00:09 appendonly.aof
然后我們?cè)俅问褂每蛻舳藢?xiě)入文件
# 再次使用redis客戶端寫(xiě)入指令 [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# redis-cli 127.0.0.1:6379> set test vv (error) NOAUTH Authentication required. 127.0.0.1:6379> auth 123 OK 127.0.0.1:6379> set k4 v4 OK 127.0.0.1:6379>
可以看到大小又增加了,由此得出我們AOF配置生效了。
# 再次查看aof文件大小,變?yōu)?39,說(shuō)明aof配置生效 [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# ll appendonly.aof -rw-r--r-- 1 root root 139 Aug 26 00:10 appendonly.aof [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]#
appendfilename ,該參數(shù)決定aof持久化文件的名字,這個(gè)就不多贅述了。 如下所示,這條配置就意味著aof文件名是appendonly
appendfilename "appendonly.aof"
dir :該參數(shù)決定aof
文件持久化位置,默認(rèn)為redis-server
的位置。
dir ./
appendfsync : 在介紹appendfsync
,我們必須介紹一下操作系統(tǒng)提供的兩個(gè)函數(shù)
- write:write操作會(huì)觸發(fā)操作系統(tǒng)延遲寫(xiě)機(jī)制,這種機(jī)制下數(shù)據(jù)一寫(xiě)到緩存區(qū)就直接返回,至于什么時(shí)候進(jìn)行刷盤(pán)由操作系統(tǒng)決定,要么緩存空間滿了刷,要么就是定時(shí)任務(wù)時(shí)間到了。
- fsync:該調(diào)用會(huì)強(qiáng)制將緩存寫(xiě)入磁盤(pán)中,所以使用這個(gè)函數(shù)進(jìn)行文件寫(xiě)入時(shí),可能存在阻塞問(wèn)題。
了解了上述兩個(gè)函數(shù)之后,我們?cè)賮?lái)聊聊這個(gè)參數(shù)值:
1. `always`:該選項(xiàng)會(huì)使得命令一旦寫(xiě)入aof_buf后,就會(huì)調(diào)用操作系統(tǒng)的fsync將指令寫(xiě)到aof物理文件中,完成操作后線程返回
2. `everysec`:該選項(xiàng)會(huì)在命令寫(xiě)入`aof_buf`后調(diào)用操作系統(tǒng)的`wirte`,完成write后線程返回。`fsync`會(huì)由專(zhuān)門(mén)的線程每秒調(diào)用一次
3. `no`:該選項(xiàng)會(huì)在命令寫(xiě)入`aof_buf`后調(diào)用操作系統(tǒng)的`write`,完成`write`后線程返回,不調(diào)用`fsync`,同步操作由操作系統(tǒng)執(zhí)行,最長(zhǎng)周期為`30s`。
所以配置時(shí),我們建議采用默認(rèn)的寫(xiě)入策略everysec
,他不會(huì)像always
造成線程阻塞亦或者像no
一樣不可控。
appendfsync everysec
no-appendfsync-on-rewrite:redis為了保證持久化aof文件時(shí)調(diào)用fsync時(shí)不會(huì)出現(xiàn)長(zhǎng)時(shí)間的卡頓,增加了該參數(shù),若設(shè)置為yes
,在redis調(diào)用fsync
期間出現(xiàn)的寫(xiě)入指令不會(huì)將其放到頁(yè)緩存(page cache)
中,僅僅做個(gè)接收,保證不阻塞。
no-appendfsync-on-rewrite yes
auto-aof-rewrite-percentage和auto-aof-rewrite-min-size(重點(diǎn)):這兩個(gè)參數(shù)決定redis何時(shí)進(jìn)行重寫(xiě),如下所示,這兩個(gè)參數(shù)分別為100和64mb,意味當(dāng)本次aof文件超過(guò)64+64*100%
就觸發(fā)redis自動(dòng)重寫(xiě)。
auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb
aof-load-truncated:若設(shè)置為yes
時(shí)在redis
加載aof
文件出錯(cuò)后會(huì)發(fā)送日志通知用戶,反之則不做任何處理也不會(huì)啟動(dòng)redis,用戶可以使用redis-check-aof
指令完成數(shù)據(jù)修復(fù)。
這個(gè)參數(shù)筆者會(huì)在后文演示。
aof-load-truncated yes
aof-rewrite-incremental-fsync:開(kāi)啟該參數(shù)后,子進(jìn)程在進(jìn)行aof重寫(xiě)時(shí),每32m就會(huì)將數(shù)據(jù)寫(xiě)到的新的aof文件中,從而避免單刷造成的線程阻塞。
aof-rewrite-incremental-fsync yes
aof-use-rdb-preamble:redis 4.0之后支持同時(shí)開(kāi)啟rdb和aof,具體后文會(huì)詳述
# rdb+aof兩種機(jī)制結(jié)合使用 aof-use-rdb-preamble yes
AOF斷電后恢復(fù)的過(guò)程是什么
我們?cè)谥暗腶of文件重命名,模擬斷電后數(shù)據(jù)丟失,首先將aof文件備份,在重啟redis,模擬斷電后數(shù)據(jù)丟失
[root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# mv appendonly.aof appendonly.aof.bak # 重啟redis服務(wù)端,打開(kāi)客戶端查看數(shù)據(jù)都丟失了 [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# redis-cli 127.0.0.1:6379> auth 123 OK 127.0.0.1:6379> keys * (empty array)
然后將備份文件還原,重啟redis。
# 將aof文件還原,并重啟redis [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# mv appendonly.aof.bak appendonly.aof mv: overwrite ‘a(chǎn)ppendonly.aof'? y [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# redis-server /root/redis/redis.conf
可以看到,數(shù)據(jù)已經(jīng)回來(lái)了。
# 再次使用redis查看,丟失的數(shù)據(jù)都回來(lái)了 [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# redis-cli 127.0.0.1:6379> auth 123 OK 127.0.0.1:6379> keys * 1) "k4" 2) "k3" 3) "k2" 4) "k1" 127.0.0.1:6379>
進(jìn)階面試題
AOF重寫(xiě)機(jī)制如何壓縮文件體積
如下圖所示,可以看到重寫(xiě)時(shí)會(huì)查看進(jìn)程內(nèi)是否存在過(guò)期數(shù)據(jù),如果數(shù)據(jù)過(guò)期則這個(gè)指令的操作也會(huì)被移除。
再一個(gè)我們之前可以存在對(duì)某個(gè)集合的元素添加操作,在重寫(xiě)時(shí)會(huì)將這些添加指令壓縮成一條指令。
AOF重寫(xiě)時(shí)是否會(huì)阻塞線程
答案是會(huì)的,但阻塞僅僅發(fā)生在fork
子進(jìn)程那段時(shí)間,如下圖所示,AOF重寫(xiě)時(shí)首先會(huì)fork一個(gè)子進(jìn)程進(jìn)行日志重寫(xiě),在此期間新寫(xiě)入的數(shù)據(jù)都會(huì)被存到的AOF緩沖區(qū)中,直到子進(jìn)程全部完成重寫(xiě)并原子覆蓋aof日志文件后,才會(huì)將這些緩沖數(shù)據(jù)寫(xiě)到新的日志文件中。
需要補(bǔ)充的是,上面提到日志重寫(xiě)期間數(shù)據(jù)都會(huì)被寫(xiě)到AOF緩沖區(qū)中,在高并發(fā)場(chǎng)景下很可能導(dǎo)致內(nèi)存被大量占用進(jìn)而導(dǎo)致進(jìn)程阻塞,所以Redis借由Linux管道技術(shù)使得在AOF日志重寫(xiě)期間的新增的數(shù)據(jù)照樣可以寫(xiě)入到新文件中。
Redis重啟后加載日志文件的順序
執(zhí)行順序?yàn)?
- 先看看有沒(méi)有AOF,若有則先加載AOF,然后執(zhí)行步驟2。
- 查看是否有RDB文件,若有再加載RDB文件。
Redis恢復(fù)數(shù)據(jù)期間文件校驗(yàn)是怎么做
在日志寫(xiě)入期間要是服務(wù)器宕機(jī)了,那么這個(gè)日志文件可能就用不了了,而解決方案也很可能簡(jiǎn)單,redis給我提供一個(gè)命令進(jìn)行fix。
例子如下,我們首先需要將一個(gè)日志文件損壞:
# 追加一個(gè)錯(cuò)誤數(shù)據(jù)到aof文件末行并殺死redis 模擬服務(wù)器宕機(jī) [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# vim appendonly.aof # 再次啟動(dòng)redis,操作數(shù)據(jù)時(shí)發(fā)現(xiàn)登錄失敗 [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# redis-server /root/redis/redis.conf [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# redis-cli Could not connect to Redis at 127.0.0.1:6379: Connection refused not connected>
然后使用日志文件進(jìn)行修復(fù)
# 使用 redis-check-aof --fix aof文件 修復(fù)文件 [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# redis-check-aof --fix appendonly.aof 0x 8b: Expected prefix '*', got: 's' AOF analyzed: size=151, ok_up_to=139, ok_up_to_line=34, diff=12 This will shrink the AOF from 151 bytes, with 12 bytes, to 139 bytes # 這里選擇y Continue? [y/N]: y Successfully truncated AOF
可以看到,經(jīng)過(guò)fix修復(fù)后的日志文件部分?jǐn)?shù)據(jù)已經(jīng)恢復(fù)了
# 重啟redis,使用客戶端連接發(fā)現(xiàn)啟動(dòng)成功且數(shù)據(jù)都還在 [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# redis-server /root/redis/redis.conf [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# redis-cli 127.0.0.1:6379> auth 123 OK OK 127.0.0.1:6379> keys * 1) "k4" 2) "k3" 3) "k2" 4) "k1"
AOF有哪些優(yōu)劣勢(shì)
優(yōu)勢(shì)如下:
- 備份機(jī)制更穩(wěn)健,丟失數(shù)據(jù)幾率低。
- 日志可讀,可以處理誤操作。
而劣勢(shì)也很明顯:
- 比RDB更占磁盤(pán)空間,畢竟RDB存放的不是二進(jìn)制文件。
- 每次AOF都進(jìn)行fsync的話,性能開(kāi)銷(xiāo)大。
- 恢復(fù)和備份速度較慢。
redis混合持久化
Redis4.0
實(shí)現(xiàn)了RDB和AOF混合方式,相比于單RDB或者單AOF更安全,執(zhí)行效率更高,它的執(zhí)行過(guò)程大抵如下:
- 初始狀態(tài)下,寫(xiě)入的指令都會(huì)以RDB的形式寫(xiě)入RDB快照文件中。
- 當(dāng)發(fā)生AOF重寫(xiě)時(shí)(bgrewriteaof ),redis會(huì)fork出一個(gè)子進(jìn)程,此時(shí)會(huì)創(chuàng)建一個(gè)新的AOF文件。
- redis將全量rdb的數(shù)據(jù)寫(xiě)到新的aof文件中。
- 隨后再將aof緩沖區(qū)的增量命令(aof_rewrite_buf_blocks)寫(xiě)到新的aof文件中。
- 完成上述操作后我們就會(huì)得到一個(gè)前半部分是RDB后半部分是AOF的aof日志文件。
- 最后將新的aof文件替換掉舊的rdb和aof文件。
參考文獻(xiàn)
面試必問(wèn)的 Redis:RDB、AOF、混合持久化:https://zhuanlan.zhihu.com/p/340082703
《Redis開(kāi)發(fā)與運(yùn)維》:https://book.douban.com/subject/26971561/
到此這篇關(guān)于Redis持久化AOF詳解的文章就介紹到這了,更多相關(guān)Redis持久化AOF內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何使用gradle將java項(xiàng)目推送至maven中央倉(cāng)庫(kù)
本文主要介紹了使用gradle將java項(xiàng)目推送至maven中央倉(cāng)庫(kù),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09基于Redis位圖實(shí)現(xiàn)系統(tǒng)用戶登錄統(tǒng)計(jì)
這篇文章主要介紹了基于Redis位圖實(shí)現(xiàn)系統(tǒng)用戶登錄統(tǒng)計(jì),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11Redis分布式鎖的實(shí)現(xiàn)方式(redis面試題)
這篇文章主要介紹了Redis分布式鎖的實(shí)現(xiàn)方式(面試常見(jiàn)),需要的朋友可以參考下2020-01-01Redis做數(shù)據(jù)持久化的解決方案及底層原理
Redis有兩種方式來(lái)實(shí)現(xiàn)數(shù)據(jù)的持久化,分別是RDB(Redis Database)和AOF(Append Only File),今天通過(guò)本文給大家聊一聊Redis做數(shù)據(jù)持久化的解決方案及底層原理,感興趣的朋友一起看看吧2021-07-07Redis中的3種特殊數(shù)據(jù)結(jié)構(gòu)詳解
在本文中,我們對(duì)三種特殊的數(shù)據(jù)類(lèi)型進(jìn)行了介紹,它們分別是geospatial(地理空間數(shù)據(jù)類(lèi)型)、HyperLogLogs和Bitmaps(位圖),這些數(shù)據(jù)類(lèi)型在不同的領(lǐng)域和應(yīng)用中發(fā)揮著重要作用,并且具有各自獨(dú)特的特性和用途,對(duì)Redis特殊數(shù)據(jù)結(jié)構(gòu)相關(guān)知識(shí)感興趣的朋友一起看看吧2024-02-02阿里云官方Redis開(kāi)發(fā)規(guī)范總結(jié)
本文主要介紹了阿里云官方Redis開(kāi)發(fā)規(guī)范總結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08