日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

本來說 redis 分3篇,但是上周寫持久化時發現持久化的內容還越多的,于是持久化就單拆一篇了。

我估計后面的主從復制、哨兵、集群內容也是不少,所以說實話,我也不知道之前說的3篇會拆成幾篇了

持久化機制的內容大綱其實很早就有了,但是實際寫的時候斷斷續續寫了有兩周。

主要細節還是挺多的,在翻源碼的過程中,會遇到一些疑惑點,也發現一些自己以前不知道的知識點,所以自己也要花點時間去搞清楚。

慢工出細活吧,本文還是有很多非常細節的內容的,如果能掌握,讓大廠面試官眼前一亮還是問題不大的。

 

正文

Redis 核心主流程

 

AOF 和 RDB 的持久化過程中,有不少操作是在時間事件 serverCron 中被觸發的。所以,這邊有必要先了解下 Redis 中的事件核心流程。

 

Redis 的服務器進程就是一個事件循環,最重要的有兩個事件:文件事件和時間事件。Redis 在服務器初始化后,會無限循環,處理產生的文件事件和時間事件。

 

文件事件常見的有:接受連接(accept)、讀取(read)、寫入(write)、關閉連接(close)等。

 

時間事件中常見的就是 serverCron,redis 核心流程中通常也只有這個時間事件。serverCron 默認配置下每100ms會被觸發一次,在該時間事件中,會執行很多操作:清理過期鍵、AOF 后臺重寫、RDB 的 save point 的檢查、將 aof_buf 內容寫到磁盤上(flushAppendOnlyFile 函數)等等。

 

Redis 的核心主流程如下圖:

面試必問的 Redis:RDB、AOF、混合持久化

 

相關源碼在 server.c、ae.c,核心方法是:main、aeProcessEvents

 

Redis 的持久化機制有哪幾種

 

RDB、AOF、混合持久化(redis4.0引入)

 

RDB的實現原理、優缺點

 

描述:類似于快照。在某個時間點,將 Redis 在內存中的數據庫狀態(數據庫的鍵值對等信息)保存到磁盤里面。RDB 持久化功能生成的 RDB 文件是經過壓縮的二進制文件。

 

命令:有兩個 Redis 命令可以用于生成 RDB 文件,一個是 SAVE,另一個是 BGSAVE。

 

開啟:使用 save point 配置,滿足 save point 條件后會觸發 BGSAVE 來存儲一次快照,這邊的 save point 檢查就是在上文提到的 serverCron 中進行。

 

save point 格式:save <seconds> <changes>,含義是 Redis 如果在 seconds 秒內數據發生了 changes 次改變,就保存快照文件。例如 Redis 默認就配置了以下3個:

save 900 1 #900秒內有1個key發生了變化,則觸發保存RDB文件
save 300 10 #300秒內有10個key發生了變化,則觸發保存RDB文件
save 60 10000 #60秒內有10000個key發生了變化,則觸發保存RDB文件

 

關閉:1)注釋掉所有save point 配置可以關閉 RDB 持久化。2)在所有 save point 配置后增加:save "",該配置可以刪除所有之前配置的 save point。

save ""

 

SAVE:生成 RDB 快照文件,但是會阻塞主進程,服務器將無法處理客戶端發來的命令請求,所以通常不會直接使用該命令。

 

BGSAVE:fork 子進程來生成 RDB 快照文件,阻塞只會發生在 fork 子進程的時候,之后主進程可以正常處理請求,詳細過程如下圖:

面試必問的 Redis:RDB、AOF、混合持久化

 

fork:在 linux 系統中,調用 fork() 時,會創建出一個新進程,稱為子進程,子進程會拷貝父進程的 page table。如果進程占用的內存越大,進程的 page table 也會越大,那么 fork 也會占用更多的時間。如果 Redis 占用的內存很大,那么在 fork 子進程時,則會出現明顯的停頓現象。

 

RDB 的優點:

1)RDB 文件是是經過壓縮的二進制文件,占用空間很小,它保存了 Redis 某個時間點的數據集,很適合用于做備份。 比如說,你可以在最近的 24 小時內,每小時備份一次 RDB 文件,并且在每個月的每一天,也備份一個 RDB 文件。這樣的話,即使遇上問題,也可以隨時將數據集還原到不同的版本。

 

2)RDB 非常適用于災難恢復(disaster recovery):它只有一個文件,并且內容都非常緊湊,可以(在加密后)將它傳送到別的數據中心。

 

3)RDB 可以最大化 redis 的性能。父進程在保存 RDB 文件時唯一要做的就是 fork 出一個子進程,然后這個子進程就會處理接下來的所有保存工作,父進程無須執行任何磁盤 I/O 操作。

 

4)RDB 在恢復大數據集時的速度比 AOF 的恢復速度要快。

 

RDB 的缺點:

1)RDB 在服務器故障時容易造成數據的丟失。RDB 允許我們通過修改 save point 配置來控制持久化的頻率。但是,因為 RDB 文件需要保存整個數據集的狀態, 所以它是一個比較重的操作,如果頻率太頻繁,可能會對 Redis 性能產生影響。所以通常可能設置至少5分鐘才保存一次快照,這時如果 Redis 出現宕機等情況,則意味著最多可能丟失5分鐘數據。

 

2)RDB 保存時使用 fork 子進程進行數據的持久化,如果數據比較大的話,fork 可能會非常耗時,造成 Redis 停止處理服務N毫秒。如果數據集很大且 CPU 比較繁忙的時候,停止服務的時間甚至會到一秒。

 

3)Linux fork 子進程采用的是 copy-on-write 的方式。在 Redis 執行 RDB 持久化期間,如果 client 寫入數據很頻繁,那么將增加 Redis 占用的內存,最壞情況下,內存的占用將達到原先的2倍。剛 fork 時,主進程和子進程共享內存,但是隨著主進程需要處理寫操作,主進程需要將修改的頁面拷貝一份出來,然后進行修改。極端情況下,如果所有的頁面都被修改,則此時的內存占用是原先的2倍。

 

相關源碼在 rdb.c,核心方法是:rdbSaveBackground、rdbSave

 

AOF的實現原理、優缺點

 

描述:保存 Redis 服務器所執行的所有寫操作命令來記錄數據庫狀態,并在服務器啟動時,通過重新執行這些命令來還原數據集。

 

開啟:AOF 持久化默認是關閉的,可以通過配置:appendonly yes 開啟。

 

關閉:使用配置 appendonly no 可以關閉 AOF 持久化。

 

AOF 持久化功能的實現可以分為三個步驟:命令追加、文件寫入、文件同步。

 

命令追加:當 AOF 持久化功能打開時,服務器在執行完一個寫命令之后,會將被執行的寫命令追加到服務器狀態的 aof 緩沖區(aof_buf)的末尾。

 

文件寫入與文件同步:可能有人不明白為什么將 aof_buf 的內容寫到磁盤上需要兩步操作,這邊簡單解釋一下。

 

Linux 操作系統中為了提升性能,使用了頁緩存(page cache)。當我們將 aof_buf 的內容寫到磁盤上時,此時數據并沒有真正的落盤,而是在 page cache 中,為了將 page cache 中的數據真正落盤,需要執行 fsync / fdatasync 命令來強制刷盤。這邊的文件同步做的就是刷盤操作,或者叫文件刷盤可能更容易理解一些。

 

在文章開頭,我們提過 serverCron 時間事件中會觸發 flushAppendOnlyFile 函數,該函數會根據服務器配置的 appendfsync 參數值,來決定是否將 aof_buf 緩沖區的內容寫入和保存到 AOF 文件。

 

appendfsync 參數有三個選項:

1)always:每處理一個命令都將 aof_buf 緩沖區中的所有內容寫入并同步到AOF 文件,即每個命令都刷盤。

 

2)everysec:將 aof_buf 緩沖區中的所有內容寫入到 AOF 文件,如果上次同步 AOF 文件的時間距離現在超過一秒鐘, 那么再次對 AOF 文件進行同步, 并且這個同步操作是異步的,由一個后臺線程專門負責執行,即每秒刷盤1次。

 

3)no:將 aof_buf 緩沖區中的所有內容寫入到 AOF 文件, 但并不對 AOF 文件進行同步, 何時同步由操作系統來決定。即不執行刷盤,讓操作系統自己執行刷盤。

 

AOF 的優點

1)AOF 比 RDB可靠。你可以設置不同的 fsync 策略:no、everysec 和 always。默認是 everysec,在這種配置下,redis 仍然可以保持良好的性能,并且就算發生故障停機,也最多只會丟失一秒鐘的數據。

 

2)AOF文件是一個純追加的日志文件。即使日志因為某些原因而包含了未寫入完整的命令(比如寫入時磁盤已滿,寫入中途停機等等), 我們也可以使用 redis-check-aof 工具也可以輕易地修復這種問題。

 

3)當 AOF文件太大時,Redis 會自動在后臺進行重寫:重寫后的新 AOF 文件包含了恢復當前數據集所需的最小命令集合。整個重寫是絕對安全,因為重寫是在一個新的文件上進行,同時 Redis 會繼續往舊的文件追加數據。當新文件重寫完畢,Redis 會把新舊文件進行切換,然后開始把數據寫到新文件上。

 

4)AOF 文件有序地保存了對數據庫執行的所有寫入操作以 Redis 協議的格式保存, 因此 AOF 文件的內容非常容易被人讀懂, 對文件進行分析(parse)也很輕松。如果你不小心執行了 FLUSHALL 命令把所有數據刷掉了,但只要 AOF 文件沒有被重寫,那么只要停止服務器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重啟 Redis , 就可以將數據集恢復到 FLUSHALL 執行之前的狀態。

 

AOF 的缺點

1)對于相同的數據集,AOF 文件的大小一般會比 RDB 文件大。

 

2)根據所使用的 fsync 策略,AOF 的速度可能會比 RDB 慢。通常 fsync 設置為每秒一次就能獲得比較高的性能,而關閉 fsync 可以讓 AOF 的速度和 RDB 一樣快。

 

3)AOF 在過去曾經發生過這樣的 bug :因為個別命令的原因,導致 AOF 文件在重新載入時,無法將數據集恢復成保存時的原樣。(舉個例子,阻塞命令 BRPOPLPUSH 就曾經引起過這樣的 bug ) 。雖然這種 bug 在 AOF 文件中并不常見, 但是相較而言, RDB 幾乎是不可能出現這種 bug 的。

 

相關源碼在 aof.c,核心方法是:feedAppendOnlyFile、flushAppendOnlyFile

 

混合持久化的實現原理、優缺點

 

描述:混合持久化并不是一種全新的持久化方式,而是對已有方式的優化。混合持久化只發生于 AOF 重寫過程。使用了混合持久化,重寫后的新 AOF 文件前半段是 RDB 格式的全量數據,后半段是 AOF 格式的增量數據。

 

整體格式為:[RDB file][AOF tail]

 

開啟:混合持久化的配置參數為 aof-use-rdb-preamble,配置為 yes 時開啟混合持久化,在 redis 4 剛引入時,默認是關閉混合持久化的,但是在 redis 5 中默認已經打開了。

 

關閉:使用 aof-use-rdb-preamble no 配置即可關閉混合持久化。

 

混合持久化本質是通過 AOF 后臺重寫(bgrewriteaof 命令)完成的,不同的是當開啟混合持久化時,fork 出的子進程先將當前全量數據以 RDB 方式寫入新的 AOF 文件,然后再將 AOF 重寫緩沖區(aof_rewrite_buf_blocks)的增量命令以 AOF 方式寫入到文件,寫入完成后通知主進程將新的含有 RDB 格式和 AOF 格式的 AOF 文件替換舊的的 AOF 文件。

 

優點:結合 RDB 和 AOF 的優點, 更快的重寫和恢復。

 

缺點:AOF 文件里面的 RDB 部分不再是 AOF 格式,可讀性差。

 

相關源碼在 aof.c,核心方法是:rewriteAppendOnlyFile

 

為什么需要 AOF 重寫

 

AOF 持久化是通過保存被執行的寫命令來記錄數據庫狀態的,隨著寫入命令的不斷增加,AOF 文件中的內容會越來越多,文件的體積也會越來越大。

 

如果不加以控制,體積過大的 AOF 文件可能會對 Redis 服務器、甚至整個宿主機造成影響,并且 AOF 文件的體積越大,使用 AOF 文件來進行數據還原所需的時間就越多。

 

舉個例子, 如果你對一個計數器調用了 100 次 INCR , 那么僅僅是為了保存這個計數器的當前值, AOF 文件就需要使用 100 條記錄。

 

然而在實際上, 只使用一條 SET 命令已經足以保存計數器的當前值了, 其余 99 條記錄實際上都是多余的。

 

為了處理這種情況, Redis 引入了 AOF 重寫:可以在不打斷服務端處理請求的情況下, 對 AOF 文件進行重建(rebuild)。

 

AOF 重寫

 

描述:Redis 生成新的 AOF 文件來代替舊 AOF 文件,這個新的 AOF 文件包含重建當前數據集所需的最少命令。具體過程是遍歷所有數據庫的所有鍵,從數據庫讀取鍵現在的值,然后用一條命令去記錄鍵值對,代替之前記錄這個鍵值對的多條命令。

 

命令:有兩個 Redis 命令可以用于觸發 AOF 重寫,一個是 BGREWRITEAOF 、另一個是 REWRITEAOF 命令;

 

開啟:AOF 重寫由兩個參數共同控制,auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size,同時滿足這兩個條件,則觸發 AOF 后臺重寫 BGREWRITEAOF。

// 當前AOF文件比上次重寫后的AOF文件大小的增長比例超過100
auto-aof-rewrite-percentage 100 
// 當前AOF文件的文件大小大于64MB
auto-aof-rewrite-min-size 64mb

 

關閉:auto-aof-rewrite-percentage 0,指定0的百分比,以禁用自動AOF重寫功能。

auto-aof-rewrite-percentage 0

 

REWRITEAOF:進行 AOF 重寫,但是會阻塞主進程,服務器將無法處理客戶端發來的命令請求,通常不會直接使用該命令。

 

BGREWRITEAOF:fork 子進程來進行 AOF 重寫,阻塞只會發生在 fork 子進程的時候,之后主進程可以正常處理請求。

 

REWRITEAOF 和 BGREWRITEAOF 的關系與 SAVE 和 BGSAVE 的關系類似。

 

相關源碼在 aof.c,核心方法是:rewriteAppendOnlyFile

 

AOF 后臺重寫存在的問題

 

AOF 后臺重寫使用子進程進行從寫,解決了主進程阻塞的問題,但是仍然存在另一個問題:子進程在進行 AOF 重寫期間,服務器主進程還需要繼續處理命令請求,新的命令可能會對現有的數據庫狀態進行修改,從而使得當前的數據庫狀態和重寫后的 AOF 文件保存的數據庫狀態不一致。

 

如何解決 AOF 后臺重寫存在的數據不一致問題

 

為了解決上述問題,Redis 引入了 AOF 重寫緩沖區(aof_rewrite_buf_blocks),這個緩沖區在服務器創建子進程之后開始使用,當 Redis 服務器執行完一個寫命令之后,它會同時將這個寫命令追加到 AOF 緩沖區和 AOF 重寫緩沖區。

 

這樣一來可以保證:

1、現有 AOF 文件的處理工作會如常進行。這樣即使在重寫的中途發生停機,現有的 AOF 文件也還是安全的。

2、從創建子進程開始,也就是 AOF 重寫開始,服務器執行的所有寫命令會被記錄到 AOF 重寫緩沖區里面。

 

這樣,當子進程完成 AOF 重寫工作后,父進程會在 serverCron 中檢測到子進程已經重寫結束,則會執行以下工作:

1、將 AOF 重寫緩沖區中的所有內容寫入到新 AOF 文件中,這時新 AOF 文件所保存的數據庫狀態將和服務器當前的數據庫狀態一致。

2、對新的 AOF 文件進行改名,原子的覆蓋現有的 AOF 文件,完成新舊兩個 AOF 文件的替換。

 

之后,父進程就可以繼續像往常一樣接受命令請求了。

 

相關源碼在 aof.c,核心方法是:rewriteAppendOnlyFileBackground

 

AOF 重寫緩沖區內容過多怎么辦

 

將 AOF 重寫緩沖區的內容追加到新 AOF 文件的工作是由主進程完成的,所以這一過程會導致主進程無法處理請求,如果內容過多,可能會使得阻塞時間過長,顯然是無法接受的。

 

Redis 中已經針對這種情況進行了優化:

1、在進行 AOF 后臺重寫時,Redis 會創建一組用于父子進程間通信的管道,同時會新增一個文件事件,該文件事件會將寫入 AOF 重寫緩沖區的內容通過該管道發送到子進程。

2、在重寫結束后,子進程會通過該管道盡量從父進程讀取更多的數據,每次等待可讀取事件1ms,如果一直能讀取到數據,則這個過程最多執行1000次,也就是1秒。如果連續20次沒有讀取到數據,則結束這個過程。

 

通過這些優化,Redis 盡量讓 AOF 重寫緩沖區的內容更少,以減少主進程阻塞的時間。

 

到此,AOF 后臺重寫的核心內容基本告一段落,通過一張圖來看下其完整流程。

面試必問的 Redis:RDB、AOF、混合持久化

 

相關源碼在 aof.c,核心方法是:aofCreatePipes、aofChildWriteDiffData、rewriteAppendOnlyFile

 

RDB、AOF、混合持久,我應該用哪一個?

 

一般來說, 如果想盡量保證數據安全性, 你應該同時使用 RDB 和 AOF 持久化功能,同時可以開啟混合持久化。

 

如果你非常關心你的數據, 但仍然可以承受數分鐘以內的數據丟失, 那么你可以只使用 RDB 持久化。

 

如果你的數據是可以丟失的,則可以關閉持久化功能,在這種情況下,Redis 的性能是最高的。

 

使用 Redis 通常都是為了提升性能,而如果為了不丟失數據而將 appendfsync 設置為 always 級別時,對 Redis 的性能影響是很大的,在這種不能接受數據丟失的場景,其實可以考慮直接選擇 MySQL 等類似的數據庫。

 

服務啟動時如何加載持久化數據

 

簡單來說,如果同時啟用了 AOF 和 RDB,Redis 重新啟動時,會使用 AOF 文件來重建數據集,因為通常來說, AOF 的數據會更完整。

 

而在引入了混合持久化之后,使用 AOF 重建數據集時,會通過文件開頭是否為“REDIS”來判斷是否為混合持久化。

 

完整流程如下圖所示:

面試必問的 Redis:RDB、AOF、混合持久化

 

相關源碼在 server.c,核心方法是:loadDataFromDisk

分享到:
標簽:Redis
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定