<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          小伙用 12 張圖講明白了 Redis 持久化!

          共 5481字,需瀏覽 11分鐘

           ·

          2022-04-11 12:21

          00 前言

          很多小伙伴都用 Redis 做緩存,那如果 Redis 服務(wù)器宕機(jī),內(nèi)存中數(shù)據(jù)全部丟失,應(yīng)該如何做數(shù)據(jù)恢復(fù)呢?有人說(shuō)很簡(jiǎn)單呀,直接從 MySQL 數(shù)據(jù)庫(kù)再讀回來(lái)就得了。

          這種方式存在兩個(gè)問(wèn)題:一是頻繁訪(fǎng)問(wèn)?MySQL 數(shù)據(jù)庫(kù),有一定的風(fēng)險(xiǎn);二是,從界面上來(lái)看,從 MySQL 讀就不如從 Redis 快。

          遠(yuǎn)哥遠(yuǎn)哥,那咋辦呀?教教我吧。

          我用中指抵著小胖的下吧,說(shuō)到:傻瓜,我們可以做持久化呀。Redis 的持久化分兩種,一種是 AOF,另一種是 RDB。來(lái),坐哥哥腿上,我給你好好說(shuō)道說(shuō)道。

          老規(guī)矩,先上張腦圖:

          0.1 什么是持久化?

          持久化(Persistence),即把數(shù)據(jù)(如內(nèi)存中的對(duì)象)保存到可永久保存的存儲(chǔ)設(shè)備中(如磁盤(pán))。持久化的主要應(yīng)用是將內(nèi)存中的對(duì)象存儲(chǔ)在數(shù)據(jù)庫(kù)中,或者存儲(chǔ)在磁盤(pán)文件中、XML 數(shù)據(jù)文件中等等。持久化是將程序數(shù)據(jù)在持久狀態(tài)和瞬時(shí)狀態(tài)間轉(zhuǎn)換的機(jī)制

          01 怎么理解 Redis 的單線(xiàn)程?

          必須聲明一點(diǎn):Redis 的單線(xiàn)程,是指?Redis 的網(wǎng)絡(luò) IO 和鍵值對(duì)讀寫(xiě)是由一個(gè)線(xiàn)程(主線(xiàn)程)完成的,這也是 Redis 對(duì)外提供鍵值存儲(chǔ)服務(wù)的主要流程。但 Redis 的其他功能,比如持久化、異步刪除、集群數(shù)據(jù)同步等,其實(shí)是由額外的線(xiàn)程執(zhí)行的。

          1.0 Redis 快的原因?

          基于內(nèi)存

          • 數(shù)據(jù)都存儲(chǔ)在內(nèi)存里,減少了一些不必要的 I/O 操作,操作速率很快。

          高效的數(shù)據(jù)結(jié)構(gòu)

          • 底層多種數(shù)據(jù)結(jié)構(gòu)支持不同的數(shù)據(jù)類(lèi)型,支持 Redis 存儲(chǔ)不同的數(shù)據(jù);
          • 不同數(shù)據(jù)結(jié)構(gòu)的設(shè)計(jì),使得數(shù)據(jù)存儲(chǔ)時(shí)間復(fù)雜度降到最低。

          合理的線(xiàn)程模型

          • I/O 多路復(fù)用模型同時(shí)監(jiān)聽(tīng)多個(gè)客戶(hù)端連接;

          • 單線(xiàn)程在執(zhí)行過(guò)程中不需要進(jìn)行上下文切換,減少了耗時(shí)。

          02 AOF 持久化

          AOF(Append Only File) 持久化是通過(guò)保存 Redis 服務(wù)器所執(zhí)行的寫(xiě)命令來(lái)記錄數(shù)據(jù)庫(kù)狀態(tài),也就是每當(dāng) Redis 執(zhí)行一個(gè)改變數(shù)據(jù)集的命令時(shí)(比如 SET), 這個(gè)命令就會(huì)被追加到 AOF 文件的末尾。

          修改 redis.conf 配置文件,默認(rèn)是 appendonly no(關(guān)閉狀態(tài)),將 no 改為 yes 即可開(kāi)啟 AOF 持久化:

          appendonly?yes

          在客戶(hù)端輸入如下命令也可,但是 Redis 服務(wù)器重啟后會(huì)失效。

          192.168.17.101:6379>?config?set?appendonly?yes
          OK

          AOF 持久化功能的實(shí)現(xiàn)可以分為命令追加(append)、文件寫(xiě)回磁盤(pán)兩個(gè)步驟。

          2.0 命令追加

          AOF 持久化功能開(kāi)啟時(shí),Redis 在執(zhí)行完一個(gè)寫(xiě)命令之后,會(huì)將被執(zhí)行的寫(xiě)命令追加到服務(wù)器狀態(tài)的?aof_buf 緩沖區(qū)的末尾,此時(shí)緩沖區(qū)的記錄還沒(méi)有寫(xiě)入到 appendonly.aof 文件中

          2.0.1 AOF 的格式

          AOF 保存的是 Redis 的寫(xiě)命令,比如:執(zhí)行命令?set testkey testvalue,它存儲(chǔ)的內(nèi)容如下圖所示:

          AOF 格式

          其中,“*3” 表示當(dāng)前命令有三個(gè)部分,每部分都是由?$+ 數(shù)字開(kāi)頭,后面緊跟著具體的命令、鍵或值。這里,數(shù)字表示這部分中的命令、鍵或值一共有多少字節(jié)。例如,?$3 set?表示這部分有 3 個(gè)字節(jié),也就是?set?命令。

          2.0.2 寫(xiě)后日志有啥優(yōu)缺點(diǎn)?

          AOF 記錄日志的方式被稱(chēng)為寫(xiě)后日志,也就是先執(zhí)行命令再記錄,而 MySQL 中的 redo log、binlog 等都是寫(xiě)前日志。它的寫(xiě)入流程是下圖這樣的:

          寫(xiě) AOF 流程

          寫(xiě)后有什么優(yōu)點(diǎn)?

          • 記錄 AOF 時(shí)不會(huì)對(duì)命令進(jìn)行語(yǔ)法檢查 ,寫(xiě)后就只記錄了執(zhí)行成功的命令。(避免保存的錯(cuò)誤的命令,恢復(fù)的時(shí)候就完?duì)僮恿耍?/section>
          • 執(zhí)行完之后再記錄,不會(huì)阻塞當(dāng)前的寫(xiě)操作

          寫(xiě)后有什么缺陷?

          • 如果執(zhí)行完一個(gè)命令還沒(méi)來(lái)得及寫(xiě)日志就宕機(jī)了會(huì)造成響應(yīng)數(shù)據(jù)丟失。
          • AOF 的寫(xiě)入由主線(xiàn)程處理,如果寫(xiě)入時(shí)出現(xiàn)較長(zhǎng)耗時(shí),那就會(huì)影響主線(xiàn)程處理后續(xù)的請(qǐng)求。

          你發(fā)現(xiàn)沒(méi)有?寫(xiě)后的兩個(gè)缺陷都是 AOF 的寫(xiě)入磁盤(pán)時(shí)相發(fā)生的,我們來(lái)看看它是怎么寫(xiě)入的呢?

          2.1 AOF 寫(xiě)入磁盤(pán)

          AOF 提供了三個(gè)選擇,也就是 AOF 配置項(xiàng)?appendfsync?的三個(gè)可選值。

          • Always,同步寫(xiě)回:每個(gè)寫(xiě)命令執(zhí)行完,立馬同步地將日志寫(xiě)回磁盤(pán);

          • Everysec(默認(rèn)),每秒寫(xiě)回:每個(gè)寫(xiě)命令執(zhí)行完,只是先把日志寫(xiě)到 AOF 文件的內(nèi)存緩沖區(qū),每隔一秒把緩沖區(qū)中的內(nèi)容寫(xiě)入磁盤(pán);

          • No,操作系統(tǒng)控制的寫(xiě)回:每個(gè)寫(xiě)命令執(zhí)行完,只是先把日志寫(xiě)到 AOF 文件的內(nèi)存緩沖區(qū),由操作系統(tǒng)決定何時(shí)將緩沖區(qū)內(nèi)容寫(xiě)回磁盤(pán)。

          2.1.0 三種策略的優(yōu)缺點(diǎn)

          針對(duì)避免主線(xiàn)程阻塞和減少數(shù)據(jù)丟失問(wèn)題,這三種寫(xiě)回策略都無(wú)法做到兩全其美。主要原因是:

          • Always(同步寫(xiě)回) 基本不丟數(shù)據(jù),但是它在每一個(gè)寫(xiě)命令后都有一個(gè)慢速的落盤(pán)操作,影響主線(xiàn)程性能;
          • No(操作系統(tǒng)控制的寫(xiě)回)在寫(xiě)完緩沖區(qū)后,繼續(xù)執(zhí)行后續(xù)的命令,但是落盤(pán)的時(shí)機(jī)已經(jīng)不在 Redis 手中了,只要 AOF 記錄沒(méi)有寫(xiě)回磁盤(pán),一旦宕機(jī)對(duì)應(yīng)的數(shù)據(jù)就丟失了;
          • Everysec(每秒寫(xiě)回)采用一秒寫(xiě)回一次的頻率,避免了 Always 的性能開(kāi)銷(xiāo),雖然減少了對(duì)系統(tǒng)性能的影響,但是如果發(fā)生宕機(jī),上一秒內(nèi)未落盤(pán)的命令操作仍然會(huì)丟失。
          三種策略的優(yōu)缺點(diǎn)

          總結(jié)一下就是:想高性能,選擇 No 策略;想高可靠性,選擇 Always 策略;允許數(shù)據(jù)有一點(diǎn)丟失,又希望性能別受太大影響,選擇 Everysec 策略。

          2.2 AOF 恢復(fù)數(shù)據(jù)

          不說(shuō)了,看圖:

          AOF 恢復(fù)數(shù)據(jù)

          2.3 AOF 重寫(xiě)

          我不知道你發(fā)現(xiàn)沒(méi)有?AOF 文件是不斷地將寫(xiě)命令追加到文件的末尾來(lái)記錄數(shù)據(jù)庫(kù)狀態(tài)的。寫(xiě)命令不斷增加,AOF 體積也越來(lái)越大。

          有些命令是執(zhí)行多次更新同一條數(shù)據(jù),但其實(shí)它是可以合并成同一條命令的。比如:LPUSH 對(duì)列表數(shù)據(jù)做了 6 次更改,但 AOF 只需要記錄最后一次更改。因?yàn)槿罩净謴?fù)時(shí),只需要執(zhí)行最后一次更改的命令即可

          為了處理這種情況,Redis 提供了 AOF 的重寫(xiě)機(jī)制。它的多變一功能,把 6 條寫(xiě)命令合并成一條。如下所示:

          LPUSH

          如果你的某些鍵有成百上千次的修改,重寫(xiě)機(jī)制節(jié)約的空間就很可觀(guān)了。

          2.3.1 觸發(fā)重寫(xiě)

          有兩種觸發(fā)的方法,一個(gè)是調(diào)用命令 BGREWRITEAOF;一個(gè)是修改配置文件參數(shù)。

          #?方式一
          192.168.17.101:6379>?BGREWRITEAOF
          Background?append?only?file?rewriting?started

          #?方式二
          auto-aof-rewrite-percentage?100?#當(dāng)前AOF文件大小和上一次重寫(xiě)時(shí)AOF文件大小的比值
          auto-aof-rewrite-min-size?64mb??#文件的最小體積

          2.3.2 重寫(xiě)步驟

          1. 創(chuàng)建子進(jìn)程進(jìn)行 AOF 重寫(xiě)
          2. 將客戶(hù)端的寫(xiě)命令追加到 AOF 重寫(xiě)緩沖區(qū)
          3. 子進(jìn)程完成 AOF 重寫(xiě)工作后,會(huì)向父進(jìn)程發(fā)送一個(gè)信號(hào)
          4. 父進(jìn)程接收到信號(hào)后,將 AOF 重寫(xiě)緩沖區(qū)的所有內(nèi)容寫(xiě)入到新 AOF 文件中
          5. 對(duì)新的 AOF 文件進(jìn)行改名,覆蓋現(xiàn)有的 AOF 文件
          重寫(xiě)步驟

          2.4 相關(guān)配置

          #?是否開(kāi)啟AOF功能
          appendonly?no

          #?AOF文件件名稱(chēng)
          appendfilename?"appendonly.aof"

          #?寫(xiě)入AOF文件的三種方式
          appendfsync?always
          appendfsync?everysec
          appendfsync?no

          #?重寫(xiě)AOF時(shí),是否繼續(xù)寫(xiě)AOF文件
          no-appendfsync-on-rewrite?no

          #?自動(dòng)重寫(xiě)AOF文件的條件
          auto-aof-rewrite-percentage?100?#百分比
          auto-aof-rewrite-min-size?64mb?#大小

          #?是否忽略最后一條可能存在問(wèn)題的指令
          aof-load-truncated?yes

          2.5 優(yōu)缺點(diǎn)

          優(yōu)點(diǎn)

          1. AOF 文件可讀性高,分析容易
          2. AOF 文件過(guò)大時(shí),自動(dòng)進(jìn)行重寫(xiě)
          3. 追加形式,寫(xiě)入時(shí)不需要再次讀取文件,直接加到末尾

          缺點(diǎn)

          1. 相同數(shù)據(jù)量下,AOF 一般比 RDB 大
          2. AOF 恢復(fù)時(shí)需要重放命令,恢復(fù)速度慢
          3. 根據(jù) fsync 策略,AOF 的速度可能慢于 RDB

          03 RDB 持久化

          RDB 持久化是指在客戶(hù)端輸入?save、bgsave?或者達(dá)到配置文件自動(dòng)保存快照條件時(shí),將 Redis 在內(nèi)存中的數(shù)據(jù)生成快照保存在名字為?dump.rdb(文件名可修改)的二進(jìn)制文件中。

          3.1 save 命令

          save 命令會(huì)阻塞 Redis 服務(wù)器進(jìn)程,直到 RDB 文件創(chuàng)建完畢為止,在 Redis 服務(wù)器阻塞期間,服務(wù)器不能處理任何命令請(qǐng)求。在客戶(hù)端輸入 save

          127.0.0.1:6379>?save
          OK

          快照生成完畢,會(huì)彈出?DB saved ondisk?的提示。

          1349:M?25?Apr?13:16:48.935?*?DB?saved?on?disk

          3.2 bgsave 命令

          bgsave 執(zhí)行時(shí),主線(xiàn)程會(huì)創(chuàng)建一個(gè)子進(jìn)程,專(zhuān)門(mén)用于寫(xiě)入 RDB 文件,避免了主線(xiàn)程的阻塞,這也是 Redis RDB 文件生成的默認(rèn)配置。

          127.0.0.1:6379>?bgsave
          Background?saving?started

          PS:bgsave 命令執(zhí)行期間 SAVE 命令會(huì)被拒絕;不能同時(shí)執(zhí)行兩個(gè) BGSAVE 命令;不能同時(shí)執(zhí)行 BGREWRITEAOF 和 BGSAVE 命令。

          3.3 bgsave 時(shí)寫(xiě)數(shù)據(jù)

          bgsave 執(zhí)行時(shí),Redis 主線(xiàn)程能正常讀寫(xiě)數(shù)據(jù)。讀操作時(shí),主線(xiàn)程和 bgsave 子線(xiàn)程互不影響;寫(xiě)操作時(shí),Redis 會(huì)利用寫(xiě)時(shí)復(fù)制技術(shù)(Copy-On-Write, COW),生成被修改數(shù)據(jù)的副本。然后 bgsave 子線(xiàn)程把副本數(shù)據(jù)寫(xiě)入 RDB。

          比如,bgsave 期間,主線(xiàn)程修改鍵值對(duì) C,過(guò)程如下:

          寫(xiě)時(shí)復(fù)制技術(shù)

          但是在這過(guò)程中發(fā)生宕機(jī)了咋辦?比如,T0 時(shí)刻做了一次快照,T0+t 時(shí)刻又做了一次。但是 t 時(shí)間內(nèi)主線(xiàn)程修改完數(shù)據(jù) 5 和 9,然后 Redis 宕機(jī)了,RDB 沒(méi)記錄到修改后的數(shù)據(jù)。

          Redis 重啟恢復(fù)數(shù)據(jù),就會(huì)出現(xiàn)數(shù)據(jù) 5 和 9 丟失的情況,沒(méi)辦法恢復(fù)。

          丟失數(shù)據(jù)

          這該咋辦?我們需要記住那些數(shù)據(jù)被修改了。

          3.4 混合持久化

          如下圖所示,記錄 t 時(shí)刻被修改的數(shù)據(jù)就需要占用額外的空間,而 Redis 是內(nèi)存數(shù)據(jù)庫(kù),空間非常寶貴。所以,直接記錄到內(nèi)存這種方式不可取。

          增量快照

          內(nèi)存開(kāi)銷(xiāo)比較小的方法是把 t 時(shí)間的增量寫(xiě)操作記錄到 AOF 日志中,這樣既保留了 RDB 的快速恢復(fù),也沒(méi)占用額外的空間。

          如圖,T1 和 T2 時(shí)刻的修改,用 AOF 日志記錄,等第二次做全量快照時(shí),清空 AOF 日志,因?yàn)榇藭r(shí)的修改都記錄到快照中了,恢復(fù)不用 AOF 日志了。

          AOF 記錄增量修改

          慶幸的是 Redis 4.0 就開(kāi)始提供了這種?RDB + AOF 的持久化方式,開(kāi)啟的配置項(xiàng)是?aof-use-rdb-preamble yes,它需要配合 AOF 的重寫(xiě)機(jī)制實(shí)現(xiàn)。

          #?開(kāi)啟混合持久化
          redis>?config?set?aof-use-rdb-preamble?yes
          OK
          #?AOF?重寫(xiě)
          redis>?BGREWRITEAOF
          Background?append?only?file?rewriting?started

          在沒(méi)有第二次做全量快照之前,它的格式是這樣的:前半部分是 RDB 格式,后半部分是 AOF 增量日志。如果這個(gè)時(shí)候宕機(jī),直接拿 appendonly.aof 恢復(fù)數(shù)據(jù)。

          appendonly.aof 格式

          3.5 RDB 優(yōu)缺點(diǎn)

          優(yōu)點(diǎn)

          1. 二進(jìn)制數(shù)據(jù),恢復(fù)時(shí)比 AOF 快
          2. RDB 的 bgsave 方式主線(xiàn)程不阻塞

          缺點(diǎn)

          1. Redis 意外宕機(jī) 時(shí),會(huì)丟失部分?jǐn)?shù)據(jù)(混合持久化可解決)
          2. 當(dāng)數(shù)據(jù)量比較大時(shí),fork 的過(guò)程是非常耗時(shí)的,fork 子進(jìn)程時(shí)是會(huì)阻塞的,在這期間 Redis 是不能響應(yīng)客戶(hù)端的請(qǐng)求的。

          04 如何選擇?

          1. 數(shù)據(jù)不能丟失時(shí),選擇內(nèi)存快照和 AOF 混合使用;
          2. 如果允許分鐘級(jí)別的數(shù)據(jù)丟失,可以只使用 RDB;
          3. 如果只用 AOF,優(yōu)先使用 everysec 的配置選項(xiàng),因?yàn)樗诳煽啃院托阅苤g取了一個(gè)平衡。

          05 數(shù)據(jù)恢復(fù)流程

          數(shù)據(jù)恢復(fù)流程

          07 總結(jié)

          本文主要講解 Redis AOF 、RDB 持久化的原理和兩者的優(yōu)缺點(diǎn),對(duì)比兩者后,我還給你總結(jié)了 Redis 混合持久化的流程。最后給了你一些選擇持久化方案的建議,希望看完你能有所收獲。

          全文將近字,張圖,希望能幫到你。好啦,以上就是狗哥關(guān)于 Redis 持久化的總結(jié)。感謝各技術(shù)社區(qū)大佬們的付出,尤其是極客時(shí)間,真的牛逼。如果說(shuō)我看得更遠(yuǎn),那是因?yàn)槲艺驹谀銈兊募绨蛏稀?/p>

          巨人的肩膀

          • 《Redis 設(shè)計(jì)與實(shí)現(xiàn)》
          • juejin.cn/post/6844903648976175118
          • blog.csdn.net/weixin_33810006/article/details/90394921
          • blog.csdn.net/wsdc0521/article/details/106765809


          往期推薦

          7000 字,四年多 Java 的 BAT 面經(jīng)分享!


          代碼review,瑞出事來(lái)了!


          synchronized 底層了解一下...




          有道無(wú)術(shù),術(shù)可成;有術(shù)無(wú)道,止于術(shù)

          歡迎大家關(guān)注Java之道公眾號(hào)


          好文章,我在看??

          瀏覽 26
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产精品色综合精品在线 | 国产黄色录像 | 亚洲成人无码高清 | 综合色婷婷| 美女色AV|