?
1.前言
面試官:你知道redis是的怎么做持久化的嗎逗柴?
我:我知道redis有兩種方式,一種是RDB亡嫌,一種是AOF
面試官:那這兩種方式具體是怎么做的嚎于,它們的區(qū)別是什么?挟冠?
我:嗯于购。。知染。肋僧。。控淡。這個(gè)我不知道
面試官:出門左拐嫌吠,不送。
嗯掺炭。辫诅。。以上場(chǎng)景很真實(shí)涧狮,都說面試造火箭炕矮,入職擰螺絲,今天我們就讓面試官再問到這個(gè)問題時(shí)者冤,把他按在地上摩擦肤视!
2.正文
我們簡(jiǎn)單的說明一下什么是redis的持久化:
用通俗的語言來說.redis的持久化就是將內(nèi)存中的數(shù)據(jù),保存的磁盤當(dāng)中,以便于數(shù)據(jù)恢復(fù).
接下來我們進(jìn)入正題,說說redis持久化的方式redis的持久化方式有兩種:RDB和AOF,
概念
RDB(redis database): 把某個(gè)時(shí)間點(diǎn)redis內(nèi)存中的數(shù)據(jù)以二進(jìn)制的形式存儲(chǔ)的一個(gè).rdb為后綴的文件當(dāng)中,也就是周期性的備份redis中的整個(gè)數(shù)據(jù),這是redis默認(rèn)的持久化方式,也就是我們說的快照(snapshot)AOF(append only file): redis每次執(zhí)行一個(gè)命令時(shí),都會(huì)把這個(gè)命令原本的語句記錄到一個(gè).aod的文件當(dāng)中,然后通過fsync策略,將命令執(zhí)行后的數(shù)據(jù)持久化到磁盤中(不包括讀命令)
RDB
RDB的兩種工作方式
1:自動(dòng)提交如下圖,這是redis中默認(rèn)的配置,它的意思就是
在900s內(nèi),有1個(gè)redis鍵有變化,就備份一次
在300s內(nèi),有10個(gè)redis鍵有變化,就備份一次
在600s內(nèi),有10000個(gè)redis鍵有變化,就備份一次
這個(gè)參數(shù)是我們可以修改的,具體的數(shù)值可以根據(jù)我們的業(yè)務(wù)量進(jìn)行匹配
2:手動(dòng)提交手動(dòng)觸發(fā)Redis進(jìn)行RDB持久化的命令有兩種:
1、save
該命令會(huì)阻塞當(dāng)前Redis服務(wù)器涉枫,執(zhí)行save命令期間邢滑,Redis不能處理其他命令,直到RDB過程完成為止愿汰。所以說當(dāng)save命令執(zhí)行期間,如果有其他命令執(zhí)行,那么只能阻塞,極大的影響了redis的性能
2困后、bgsave
執(zhí)行bgsave命令的時(shí)候,redis會(huì)自己fork出一條子進(jìn)程,由這條子進(jìn)程去執(zhí)行,這樣就不會(huì)影響到客戶端對(duì)于redis 的正常操作 有意思的是,我們都知道,進(jìn)程與進(jìn)程之間的內(nèi)存不是共享的,那么子進(jìn)程是如何獲取到主進(jìn)程的內(nèi)存數(shù)據(jù)呢?
真像是在主進(jìn)程fork子進(jìn)程的同時(shí),會(huì)把自己內(nèi)存中的數(shù)據(jù)同時(shí)復(fù)制一份給子進(jìn)程,這樣就相當(dāng)于子進(jìn)程可以讀取到主進(jìn)程的數(shù)據(jù)了,然后子進(jìn)程就可以愉快的進(jìn)行io操作了.(將內(nèi)存中的數(shù)據(jù)寫入磁盤中).用心的小伙伴可能已經(jīng)發(fā)現(xiàn)了,既然主進(jìn)程要把自己的數(shù)據(jù)復(fù)制一份給子進(jìn)程,那么就是說,會(huì)有雙倍的內(nèi)存占用.簡(jiǎn)單點(diǎn)來講,假如你的redis在未fork子進(jìn)程時(shí)就占用了5G內(nèi)存,那么你的服務(wù)器剩余可用內(nèi)存至少要達(dá)到5G才可正常的進(jìn)行fork操作,有的小伙伴可能會(huì)問,那么這個(gè)復(fù)制內(nèi)存的操作是立即執(zhí)行的嗎,其實(shí)并不是的,正常情況下redis的服務(wù)大部分都是讀操作,在fork子進(jìn)程的時(shí)候,子進(jìn)程其實(shí)并沒有直接復(fù)制一份主進(jìn)程的數(shù)據(jù),而是給他分配了一個(gè)虛擬的內(nèi)存地址,指向了父進(jìn)程的內(nèi)存地址,知道父進(jìn)程的內(nèi)存數(shù)據(jù)發(fā)生改變的時(shí)候才會(huì)進(jìn)行復(fù)制內(nèi)存的操作. 又有一個(gè)問題來了,如果在fork期間客戶端又發(fā)起了新的操作,redis會(huì)怎樣做呢,答案相信大家都猜到了,當(dāng)然是等著了,畢竟redis是單線程的,fork這個(gè)過程結(jié)束后,redis的子進(jìn)程就會(huì)進(jìn)行持久化操作了,所以redis主進(jìn)程理所應(yīng)當(dāng)?shù)木蛣?chuàng)建了一份新的rdb文件,直到子進(jìn)程完成持久化操作后,才會(huì)刪除掉之前的rdb文件,以這份新的rdb文件代替.
所以大家也發(fā)現(xiàn)了,fork的時(shí)間長短其實(shí)是跟當(dāng)時(shí)redis中的數(shù)據(jù)量有很大關(guān)系的,在其他條件恒定的情況下,隨著數(shù)據(jù)量的增大,redis 的fork操作時(shí)間也會(huì)變長.
為了性能,基本上 Redis 內(nèi)部所有的RDB操作都是采用 bgsave 命令,也就是自動(dòng)提交乐纸。
講了這么多,我們來總結(jié)一下:
RDB的優(yōu)點(diǎn):
1.它是將某一時(shí)間點(diǎn)redis內(nèi)的所有數(shù)據(jù)保存下來,所以當(dāng)我們做大型的數(shù)據(jù)恢復(fù)時(shí),RDB的恢復(fù)速度會(huì)很快,
2.由于RDB的FROK子進(jìn)程這種機(jī)制,隊(duì)友給客戶端提供讀寫服務(wù)的影響會(huì)非常小
RDB的缺點(diǎn): 1:假設(shè)我們定時(shí)5分鐘備份一次,在10:00的時(shí)候redis備份了數(shù)據(jù),但是如果在10:04的時(shí)候服務(wù)掛了,那么我們就會(huì)丟失在10:00到10:04的整個(gè)數(shù)據(jù)
2:我們前面講了,fork子進(jìn)程這個(gè)過程是和redis的數(shù)據(jù)量有很大關(guān)系的,如果數(shù)據(jù)量很大,那么很有可能會(huì)使redis暫停幾秒
AOF
AOF 重寫: 我們知道AOF是不斷的將寫命令追加到一個(gè)后綴叫.aof 的文件當(dāng)中的,那么問題來了,隨著我們不斷的寫命令,.aof文件越來越大,那么redis會(huì)做什么操作呢? 我們舉個(gè)簡(jiǎn)單的例子.
set a 10
del a
set a 10
del a
我們執(zhí)行了以上四條命令,正常來說,就會(huì)在.aof文件當(dāng)中存在這四條命令的身影,但是我們發(fā)現(xiàn),其實(shí)當(dāng)我們執(zhí)行完這四條命令,我們根本沒有修改數(shù)據(jù)的內(nèi)容,要知道,redis的本質(zhì)就是存儲(chǔ)數(shù)據(jù)的,只要數(shù)據(jù)內(nèi)容不發(fā)生改變,即使做再多的操作也是沒有意義的,redis自然也考慮到了這一點(diǎn),所以它會(huì)自己對(duì).aof文件進(jìn)行優(yōu)化,重建.aof文件,這個(gè)文件中包含了當(dāng)前數(shù)據(jù)所需要的的最少的命令集 (如:a + 1,a + 1,a + 1 這三個(gè)命令會(huì)合成為a + 3 這一個(gè)命令). 當(dāng)然redis并不會(huì)讓主進(jìn)程進(jìn)行這個(gè)操作,為了防止阻塞,在執(zhí)行重寫操作期間會(huì)設(shè)置一個(gè)aof重寫緩沖區(qū),僅僅用于在后臺(tái)進(jìn)程重寫期間操灿,將發(fā)生的數(shù)據(jù)庫讀寫命令寫入到重寫緩沖區(qū)锯仪,之后當(dāng)重寫子進(jìn)程完成重寫后,向服務(wù)器主進(jìn)程發(fā)送一個(gè)信號(hào)趾盐,此時(shí)服務(wù)器主進(jìn)程將aof重寫緩沖區(qū)中的命令追加到新的aof文件中去,用新的aof文件替換掉舊的aof文件小腊。
命令同步到磁盤的三種方式:
1:appendfsync no
Redis不會(huì)主動(dòng)調(diào)用fsync去將AOF日志內(nèi)容同步到磁盤,具體的操作依賴于操作系統(tǒng),對(duì)大多數(shù)Linux操作系統(tǒng)救鲤,是每30秒進(jìn)行一次fsync,將緩沖區(qū)中的數(shù)據(jù)寫到磁盤上秩冈。
2:appendfsync everysec
Redis會(huì)默認(rèn)每隔一秒進(jìn)行一次fsync調(diào)用,也就是說一次將一秒內(nèi)的所有命令同步到磁盤中
3:appednfsync always
每次寫操作都會(huì)調(diào)用一次fsync
AOF 的優(yōu)點(diǎn):
1.AOF可以更好的保護(hù)數(shù)據(jù)不丟失本缠,一般AOF會(huì)以每隔1秒,通過后臺(tái)的一個(gè)線程去執(zhí)行一次fsync操作入问,如果redis進(jìn)程掛掉丹锹,最多丟失1秒的數(shù)據(jù)。
2.AOF是將命令直接追加在文件末尾的,寫入性能非常高芬失。
3.AOF日志文件的命令通過非抽故颍可讀的方式進(jìn)行記錄,這個(gè)非常適合做災(zāi)難性的誤刪除緊急恢復(fù)棱烂,如果某人不小心用flushall命令清空了所有數(shù)據(jù)租漂,只要這個(gè)時(shí)候還沒有執(zhí)行rewrite,那么就可以將日志文件中的flushall刪除颊糜,進(jìn)行恢復(fù)哩治。
AOF 的缺點(diǎn):
1.對(duì)于同一份數(shù)據(jù)源來說,一般情況下AOF文件比RDB數(shù)據(jù)快照要大。
2.由于.aof每次命令都會(huì)寫入,那么相對(duì)于RDB來說需要消耗的性能也就更多衬鱼。
3.數(shù)據(jù)恢復(fù)比較慢业筏,不適合做冷備。
3.總結(jié)
redis有兩種持久化的方式鸟赫,一種是RDB蒜胖,一種是AOP,所謂RDB就是段時(shí)間的用快照的方式將redis中的所有數(shù)據(jù)存儲(chǔ)下來,并且通過fork子進(jìn)程的方式去持久化的惯疙,由于redis通常是用來讀取數(shù)據(jù)的翠勉,所有中間有一層優(yōu)化就是寫時(shí)持久化(進(jìn)程與進(jìn)程之間內(nèi)存不共享,再redis數(shù)據(jù)發(fā)生變動(dòng)時(shí)再fork完成持久化)霉颠,而AOF就是存儲(chǔ)一條條執(zhí)行的redis命令(不包括查詢命令)对碌,通過命令的方式完成持久化,并且中間還會(huì)有AOF重寫的操作蒿偎,主要就是為了節(jié)省空間朽们。