<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>

          Redis 的持久化

          共 5631字,需瀏覽 12分鐘

           ·

          2021-05-27 16:50

          點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”

          優(yōu)質(zhì)文章,第一時(shí)間送達(dá)

            作者 |  常軒 

          來源 |  urlify.cn/faauM3

          Redis 是一個(gè)非關(guān)系型的內(nèi)存數(shù)據(jù)庫(kù),使用內(nèi)存存儲(chǔ)數(shù)據(jù)是它能夠進(jìn)行快速存取數(shù)據(jù)的原因之一。

          在實(shí)際應(yīng)用中,常有人提倡把 Redis 只作為一種能夠提高用戶體驗(yàn)的組件來使用, 也就是說即使 Redis 服務(wù)掛掉之后也要保證系統(tǒng)正常使用。不過,在很多系統(tǒng)中還是希望既能發(fā)揮 Redis 基于內(nèi)存快速存取的特性,又希望機(jī)器斷電或 Redis服務(wù)停止后數(shù)據(jù)不丟失。所以,才引出了 Redis 的持久化功能。

          在許多技術(shù)文章中,提到 Redis 的持久化時(shí)往往都會(huì)直接拋出兩個(gè)名詞 RDB 和 AOF。然后接下來就是分別介紹這兩個(gè)名詞。當(dāng)然,如果要談 Redis 的持久化肯定避免不了講 RDB 和 AOF,但這是介紹持久化最恰當(dāng)?shù)姆绞絾幔窟@樣的文章是不是顯得有些生硬呢?所以,在嘗試弄明白一個(gè)事物的原理時(shí)一定要從頭到尾的思考它存在的意義?為了解決什么問題?采用了什么方式?達(dá)到了什么目的?自己有沒有其它的方案?這樣從問題的源頭切入,才能對(duì)這個(gè)事物理解的更加深刻,從而能夠更好的幫助自己進(jìn)行舉一反三。而不是人云亦云,對(duì)于一些知識(shí)僅僅是背誦下來,這種死記硬背下來的知識(shí)在腦海里的保質(zhì)期也是短的可憐。

          在前面,我們已經(jīng)提到為什么需要引入持久化?簡(jiǎn)單的來說持久化就是把內(nèi)存中的數(shù)據(jù)存儲(chǔ)到外存上,這樣服務(wù)停止后,當(dāng)再啟動(dòng)的時(shí)候就可以把外存的數(shù)據(jù)讀取到內(nèi)存中從而達(dá)到了不丟失數(shù)據(jù)的目的。

          1、RDB

          如果讓你設(shè)計(jì)一個(gè)持久化的方案,你會(huì)怎么做呢?(假裝絞盡腦汁… …)首先,我們可以使用一種簡(jiǎn)單的策略,將 Redis 中所有的數(shù)據(jù)按照一定格式全部寫到磁盤上,即創(chuàng)建數(shù)據(jù)的快照文件。然后,你為了盡量保證不丟數(shù)據(jù)需要考慮使用實(shí)時(shí)寫還是定時(shí)寫,又或者用其它策略。其實(shí),現(xiàn)在的你已經(jīng)在嘗試著去實(shí)現(xiàn) RDB (Redis Database)持久化的機(jī)制了。所以,你看它其實(shí)并不難。萬丈高樓從地起,先從一個(gè)簡(jiǎn)單的 idea 開始,逐漸去完善它,豐富它的過程便是解決問題的過程。例如用這種思路去學(xué)習(xí)計(jì)算機(jī)網(wǎng)絡(luò)也是同樣適用的,你可以給自己出一個(gè)問題“如何讓兩臺(tái)電腦進(jìn)行通信?”,自己想辦法解決這個(gè)問題的過程肯定會(huì)比在計(jì)算機(jī)網(wǎng)絡(luò)課堂上收獲的知識(shí)更多,也更牢固。

          盡管不需要我們寫代碼來實(shí)現(xiàn) RDB 持久化,但是并不妨礙我們來思考一下假如讓我們來實(shí)現(xiàn)的話大概會(huì)遇到哪些問題?例如:什么時(shí)候生成數(shù)據(jù)快照?文件數(shù)據(jù)格式的定義?如果在主進(jìn)程中進(jìn)行持久化,阻塞客戶端的請(qǐng)求后會(huì)不會(huì)有影響?接下來,我們就看一下 RDB 是如何做的吧。

          1.1基本命令

          在 Redis 中,提供了兩個(gè) RDB 持久化的命令: SAVE 和 BGSAVE 。執(zhí)行 SAVE 時(shí),Redis 服務(wù)會(huì)停止處理任何客戶端的命令請(qǐng)求;執(zhí)行 BGSAVE 時(shí),Redis 服務(wù)則會(huì)創(chuàng)建一個(gè)子進(jìn)程,由子進(jìn)程來負(fù)責(zé)數(shù)據(jù)的持久化,而此時(shí) Redis 服務(wù)就可以正常處理客戶端的請(qǐng)求。

          BGSAVE 解決了我們對(duì)于持久化時(shí)是否會(huì)影響 Redis 服務(wù)處理客戶端的請(qǐng)求的擔(dān)心。

          1.2自動(dòng)間隔性保存

          自動(dòng)間隔性保存,則解決了“什么時(shí)候生成數(shù)據(jù)快照?”的問題。在 Redis 的配置文件中我們可以寫入以下配置:

          save 600 1
          save 300 10
          save 60 100
          save 30 1000

          上面的配置表示,如果在 600 秒內(nèi)對(duì)數(shù)據(jù)庫(kù)進(jìn)行了 1 次修改,就執(zhí)行執(zhí)行一次 BGSAVE 命令;如果在 300 秒內(nèi)對(duì)數(shù)據(jù)庫(kù)進(jìn)行了 10 次修改,就執(zhí)行一次 BGSAVE 命令;以此類推。你可以根據(jù)你的業(yè)務(wù)場(chǎng)景,配置 save 的參數(shù),也不僅僅局限于 4 條配置。

          實(shí)現(xiàn)原理

          在 Redis 啟動(dòng)時(shí),會(huì)把上述配置存儲(chǔ)到 Redis 服務(wù)器的狀態(tài)中,具體的結(jié)構(gòu)體則是 redisServer,存儲(chǔ) save 參數(shù)的結(jié)構(gòu)體為 saveparam。

           1 // Redis 服務(wù)器狀態(tài)信息結(jié)構(gòu)體
           2 struct redisServer {
           3     // ... ...
           4  
           5     // 記錄多個(gè) save 配置參數(shù)
           6     struct saveparam *saveparams;
           7     // 修改次數(shù)計(jì)數(shù)器
           8     long long dirty;
           9     // 上次執(zhí)行保存的時(shí)間
          10     time_t lastsave;
          11  
          12     // ... ...
          13 }
          14 // Save 參數(shù)結(jié)構(gòu)體 saveparam
          15 struct saveparam {
          16     // 秒數(shù)
          17     time_t seconds;
          18     // 修改數(shù)
          19     int changes;
          20 }

          看到上面 redisServer 結(jié)構(gòu)體的屬性信息,你心里應(yīng)該有答案了吧?dirty 表示的是自從上次執(zhí)行 SAVE 或者 BGSAVE 命令完成之后對(duì)數(shù)據(jù)庫(kù)進(jìn)行修改的次數(shù);lastsave 表示的是上次成功執(zhí)行SAVE 或者 BGSAVE 命令的時(shí)間。這個(gè)時(shí)候,如果再有個(gè)機(jī)制能夠定時(shí)檢查是否有滿足條件的配置參數(shù)就可以了。

          Redis 提供了一個(gè)周期性操作函數(shù) serverCron,每 100 ms 會(huì)執(zhí)行一次。它其中的一項(xiàng)工作就是來檢查是否有符合條件的 save 參數(shù),如果存在符合條件的參數(shù)則執(zhí)行 BGSAVE 命令,執(zhí)行完畢之后將 dirty 和 lastsave 的值重置。相信只要有基礎(chǔ)的編程知識(shí),根據(jù)這些變量就能實(shí)現(xiàn)這個(gè)檢查的過程吧。

          1.3文件結(jié)構(gòu)


          在上圖中,大寫字母的單詞表示的常量,小寫字母單詞則是變量和數(shù)據(jù)。RDB 文件開頭的“REDIS”是我們習(xí)慣稱為的魔數(shù),類似于 class 文件的 COFFEE,用來識(shí)別文件類型;緊接著長(zhǎng)度為四個(gè)字節(jié)的 db_version 記錄的是 RDB 文件的版本號(hào);database 表示的是所存儲(chǔ)的數(shù)據(jù);EOF 則表明數(shù)據(jù)內(nèi)容結(jié)束了;check_sum 的值是整個(gè)文件的校驗(yàn)和,用來檢查文件是否損壞。

          2、AOF

          其實(shí)持久化數(shù)據(jù)除了 RDB 這種方式,肯定會(huì)有同學(xué)能想到另一種方式,就是把服務(wù)端執(zhí)行的所有客戶端請(qǐng)求增加、修改和刪除等會(huì)改變數(shù)據(jù)的命令全都存儲(chǔ)起來。通過存儲(chǔ)這些命令數(shù)據(jù),在遇到機(jī)器宕機(jī)和服務(wù)進(jìn)程異常中斷的情況下重啟服務(wù)時(shí)只要執(zhí)行一遍這些持久化的命令即可恢復(fù)之前的數(shù)據(jù)了。(也是一個(gè)相當(dāng)好的辦法呀!)

          原理就是如此,那么問題來了,假如同樣讓你來實(shí)現(xiàn)這個(gè)過程,你會(huì)考慮到哪些問題呢?

          一是性能問題,執(zhí)行完命令之后是否直接將此命令持久化到磁盤上還是由操作系統(tǒng)控制文件同步?在這個(gè)問題上如何做取舍?二是文件大小問題,隨著 Redis 服務(wù)運(yùn)行越來越久,數(shù)據(jù)文件勢(shì)必會(huì)越來越大?應(yīng)該使用什么辦法解決?… …

          我們來看下 Redis 的 AOF 的過程吧!

          2.1持久化過程

          首先,通過在配置文件中增加一行配置 appendonly yes 來開啟 AOF 持久化。

          像 RDB 機(jī)制所依賴 redisServer 結(jié)構(gòu)體中的 saveparams、dirty、lastsave 參數(shù)一樣,AOF 的實(shí)現(xiàn)依賴 redisServer 結(jié)構(gòu)體中的 aof_buf 參數(shù)。

          1 struct redisServer{
          2     // ... ...
          3  
          4     // AOF 緩沖區(qū)
          5     sds aof_buf;
          6  
          7     // ... ...
          8 }

          aof_buf 參數(shù)用來以協(xié)議格式緩存會(huì)對(duì)數(shù)據(jù)進(jìn)行變更的命令。

          在 Redis 服務(wù)器執(zhí)行完命令,并將命令以協(xié)議的格式追加到 aof_buf 緩沖區(qū)之后,在當(dāng)前這個(gè)事件循環(huán)結(jié)束之前,Redis 還會(huì)調(diào)用一個(gè)函數(shù) flushAppendOnlyFile,這個(gè)函數(shù)會(huì)根據(jù)配置文件中 appendfsync 的值來決定接下來的持久化行為。appendfsync 有三個(gè)可選值,分別是 always、everysec、no

          • always: 將 aof_buf 緩沖區(qū)中的內(nèi)容寫入并同步到 AOF 文件。(性能最低,安全最高)

          • everysec: 將 aof_buf 緩沖區(qū)中的內(nèi)容寫入到 AOF 文件,如果上次同步 AOF 文件的時(shí)間距離現(xiàn)在超過一秒鐘,那么再次對(duì) AOF 文件同步,并且這個(gè)同步是由一個(gè)線程專門負(fù)責(zé)的。(同時(shí)兼顧性能與安全,推薦)

          • no: 將 aof_buf 緩沖區(qū)中的內(nèi)容寫入到 AOF 文件,但并不負(fù)責(zé)對(duì) AOF 文件的同步,把同步的控制權(quán)交由操作系統(tǒng)控制。(性能最高,安全最低)

          以上就是 AOF 持久化的基本過程。

          2.2數(shù)據(jù)載入

          由于命令數(shù)據(jù)是以協(xié)議格式存儲(chǔ)至文件中的,所以在啟動(dòng) Redis 服務(wù)時(shí)檢測(cè)到 AOF 文件的存在后會(huì)啟動(dòng)載入程序。(如果 RDB 和 AOF 持久化的文件同時(shí)存在則會(huì)優(yōu)先載入 AOF 文件數(shù)據(jù))

          啟動(dòng)載入程序后,其載入過程如下圖所示:

          2.3AOF 重寫

          在前面,我們提到 AOF 的這種機(jī)制會(huì)造成 AOF 數(shù)據(jù)文件越來越大,并且可能會(huì)存在許多無意義的命令。例如,先執(zhí)行了一個(gè)命令 set chang xuan ,隨后又執(zhí)行了命令 del chang 。其實(shí)這兩條語句都會(huì)被持久化到 AOF 文件中,但實(shí)際上除了能證明曾經(jīng)執(zhí)行過這兩條命令之外對(duì)于我們要持久化數(shù)據(jù)的目的而言并沒有什么作用。

          對(duì)此,Redis 提供了 AOF 重寫的機(jī)制。

          Redis 的 AOF 重寫其實(shí)是根據(jù)當(dāng)前存儲(chǔ)的數(shù)據(jù),生成命令的過程。并且會(huì)采用一些策略盡量減小 AOF 文件的大小,例如對(duì)于 List 中的數(shù)據(jù)會(huì)盡量使用較少的命令操作較多的數(shù)據(jù)。當(dāng)然,如果在當(dāng)前進(jìn)程中進(jìn)行重寫處理并且數(shù)據(jù)量特別大的情況下肯定會(huì)阻塞客戶端的請(qǐng)求,所以和 RDB 一樣,Redis 提供了 AOF 后臺(tái)重寫的機(jī)制。

          后臺(tái)重寫(BGREWRITEAOF)

          AOF 通過 fork 子進(jìn)程的方式進(jìn)行后臺(tái)重寫有兩個(gè)優(yōu)點(diǎn):

          1. 重寫期間服務(wù)器進(jìn)程可以繼續(xù)處理請(qǐng)求。

          2. 子進(jìn)程帶有服務(wù)器進(jìn)程的數(shù)據(jù)副本,能充分利用操作系統(tǒng)提供的寫時(shí)復(fù)制機(jī)制從而提升效率,還可以在避免使用鎖的情況下保證數(shù)據(jù)的安全性。

          天下沒有免費(fèi)的午餐,這種方式還帶來一個(gè)問題。就是在使用子進(jìn)程重寫期間,如果父進(jìn)程還在處理著客戶端請(qǐng)求,如何保證重寫后 AOF 文件數(shù)據(jù)的一致性呢?

          對(duì)于這個(gè)問題,Redis 設(shè)置了一個(gè) AOF 重寫緩沖區(qū)。在子進(jìn)程被創(chuàng)建后,Redis 服務(wù)器就會(huì)啟用這個(gè)重寫緩沖區(qū)。在將命令以協(xié)議格式追加到 AOF 緩沖區(qū)之后,同時(shí)也會(huì)追加到 AOF 重寫緩沖區(qū)。

          當(dāng)子進(jìn)程完成重寫工作后會(huì)向父進(jìn)程發(fā)送一個(gè)信號(hào)。父進(jìn)程接收到信后之后會(huì)進(jìn)行調(diào)用相關(guān)函數(shù),進(jìn)行以下工作:

          1. 將 AOF 重寫緩沖區(qū)中的內(nèi)容寫入到新的 AOF 文件中。

          2. 對(duì)新的 AOF 文件進(jìn)行改名,原子地覆蓋現(xiàn)有的 AOF 文件,完成新舊文件的替換。

          這時(shí),就完成了一次 AOF 后臺(tái)重寫。

          3、總結(jié)

          通過前文內(nèi)容,我們可以大致清楚 Redis 所提供的 RDB 和 AOF 兩種持久化機(jī)制的過程以及基本原理。它們各有特點(diǎn),也各有適合使用的場(chǎng)景所以并不能說誰一定比誰好。通過搭配使用,能夠確保線上環(huán)境數(shù)據(jù)的安全性就是最好的。


          感謝點(diǎn)贊支持下哈 

          瀏覽 53
          點(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>
                  国产寡妇婬乱A毛片91精品 | 精品久久久久久 | 免费一级片免费 | 热久久最新地址 | 韩国1级毛片 |