Redis持久化解讀
Redis 是內(nèi)存級數(shù)據(jù)庫,其數(shù)據(jù)存儲在內(nèi)存中,因此能夠提供快速的讀寫速度。但我們知道內(nèi)存屬于掉電易失存儲器,一旦斷電,存儲在內(nèi)存中的數(shù)據(jù)就會丟失。
在服務(wù)器重啟和 Redis 服務(wù)重啟后數(shù)據(jù)都會丟失。因此 Redis 提供了三種持久化方式:RDB(快照持久化),AOF(追加文件持久化),混合持久化(混合使用 AOF 日志和內(nèi)存快照)。其中AOF 文件的內(nèi)容是操作命令,RDB 文件的內(nèi)容是二進(jìn)制數(shù)據(jù)。
RDB快照
RDB快照是一種將Redis數(shù)據(jù)庫狀態(tài)保存到磁盤上的機(jī)制,Redis提供了兩個命令:save , bgsave。
這兩個命令實際上都會生成一份RDB文件,RDB存儲了執(zhí)行命令時的 Redis 的所有數(shù)據(jù),在 Redis 啟動時,會自動加載RDB文件恢復(fù)數(shù)據(jù)。Redis并沒有手動加載RDB文件的命令。
save與bgsave
save 命令是在主線程下執(zhí)行,由于和執(zhí)行操作命令在同一個線程,所以如果寫入 RDB 文件的時間太長,會阻塞主線程。
bgsave 命令會創(chuàng)建一個子進(jìn)程執(zhí)行 save 命令,主進(jìn)程不會阻塞。
Redis可以通過配置文件的選項來實現(xiàn)每隔一段時間自動執(zhí)行一次 bgsava 命令:
save <seconds> <changes>
- <seconds>:自上次保存后經(jīng)過的時間(以秒為單位)。
- <changes>:在這個時間段內(nèi)至少有多少個鍵被改變。
使用示例: 上次快照以來有 60 秒并且至少有 1000 個鍵被改變,則自動執(zhí)行 bgsave。
save 60 1000
我們可以設(shè)置多個 save ,只要有一個條件滿足就會執(zhí)行 bgsave。
save 900 1 save 300 10 save 60 10000
bgsave 會先 fork 創(chuàng)建出子進(jìn)程,在 Linux 中 fork 創(chuàng)建出的子進(jìn)程會復(fù)制父進(jìn)程的頁表,與父進(jìn)程共享一份物理內(nèi)存。
這種方式減少了創(chuàng)建子進(jìn)程時的性能損耗,從而加快創(chuàng)建子進(jìn)程的速度,避免主進(jìn)程阻塞。創(chuàng)建子進(jìn)程后,子進(jìn)程只讀,同時將數(shù)據(jù)存儲在 RDB 文件中。
當(dāng)執(zhí)行命令的主線程內(nèi)存數(shù)據(jù)也都是只讀操作時,主線程和 bgsave 子進(jìn)程相互不影響。當(dāng)主進(jìn)程對內(nèi)存數(shù)據(jù)修改時會觸發(fā)中斷,中斷處理程序會申請一份物理內(nèi)存重新映射到修改的虛擬內(nèi)存,這個過程叫做寫時拷貝。
因此,當(dāng)主進(jìn)程執(zhí)行寫操作時,對數(shù)據(jù)的修改不會影響到子進(jìn)程,子進(jìn)程持久化的仍是執(zhí)行 fork 命令時刻的數(shù)據(jù)。 因此會產(chǎn)生數(shù)據(jù)丟失。
在極端情況下,如果所有的共享內(nèi)存都被修改,則此時的內(nèi)存占用是原先的 2 倍。所以,針對寫操作多的場景,我們要留意下快照過程中內(nèi)存的變化,防止內(nèi)存被占滿了。
RDB優(yōu)缺點(diǎn)
RDB優(yōu)點(diǎn):
- 快速恢復(fù): RDB 文件是二進(jìn)制格式,可以非??焖俚丶虞d到內(nèi)存中,實現(xiàn)Redis服務(wù)的快速啟動。
- 數(shù)據(jù)備份: RDB 文件可以很容易地被復(fù)制到其他服務(wù)器或備份存儲中,適合于進(jìn)行數(shù)據(jù)備份和災(zāi)難恢復(fù)。
- 空間緊湊: 由于RDB文件只包含最終的數(shù)據(jù),而不是每一條寫命令,所以通常比AOF文件更緊湊。
- 減少I/O操作: 相比于AOF持久化,RDB不需要記錄每一條寫操作命令,因此減少了I/O操作。
- 適合大規(guī)模數(shù)據(jù)恢復(fù): 由于RDB文件包含了數(shù)據(jù)集的全量快照,適合于大規(guī)模數(shù)據(jù)的恢復(fù)。
RDB缺點(diǎn):
- 數(shù)據(jù)丟失風(fēng)險:如果兩次快照之間Redis發(fā)生故障,那么這段時間內(nèi)的數(shù)據(jù)將丟失。
- 數(shù)據(jù)完整性不高:RDB無法保證數(shù)據(jù)的完整性和一致性。
- 阻塞:盡管 bgsave 是在后臺異步執(zhí)行的,但在生成RDB文件時,如果數(shù)據(jù)集非常大,仍然可能會短暫地阻塞主線程。
- 不適合高頻率寫操作的場景:在寫操作非常頻繁的場景,會頻繁生成RDB快照對性能產(chǎn)生影響。
AOF日志
AOF日志持久化并不是直接保存 Redis 中的數(shù)據(jù),而是記錄Redis中執(zhí)行的所有寫操作命令。每當(dāng)Redis執(zhí)行一個寫操作命令,該命令會被追加到AOF文件中。
在 Redis 中 AOF 持久化功能默認(rèn)是不開啟的,需要我們修改 Redis.conf 配置文件中的以下參數(shù)
- appendonly yes:開啟AOF持久化。
- appendfilename "appendonly.aof":指定AOF文件的名稱。
Redis 會先執(zhí)行命令,執(zhí)行命令成功后再將命令記錄到 AOF 日志中,如果先寫入 AOF 文件還需要檢查命令是否執(zhí)行成功,如果命令執(zhí)行失敗還需要額外操作。先執(zhí)行命令也保證了AOF 不會阻塞當(dāng)前寫操作命令的執(zhí)行(但可能會阻塞下一個命令的執(zhí)行),因為當(dāng)寫操作命令執(zhí)行成功后,才會將命令記錄到 AOF 日志。
AOF持久化,會先將命令寫入內(nèi)存緩沖區(qū)中。這個內(nèi)存緩沖區(qū)稱為 AOF 緩沖區(qū)。然后再通過 wirte系統(tǒng)調(diào)用寫入到磁盤上的 AOF 文件。但 wirte寫入實際上是將數(shù)據(jù)拷貝到內(nèi)核緩存區(qū),由內(nèi)核決定何時進(jìn)行磁盤IO。如果系統(tǒng)宕機(jī),而緩沖區(qū)數(shù)據(jù)沒有寫入磁盤,這部分?jǐn)?shù)據(jù)就會丟失。
AOF寫回策略
Redis可以通過fsync或fdatasync系統(tǒng)調(diào)用來請求操作系統(tǒng)將內(nèi)核緩存區(qū)中的數(shù)據(jù)強(qiáng)制刷新到磁盤上。
AOF提供了三種寫回策略: always ,everysec , no。
- always:每次寫操作命令執(zhí)行完后,同步將 AOF 日志數(shù)據(jù)寫回硬盤。即每次執(zhí)行后都調(diào)用 fsync。
- everysec :每次寫操作命令執(zhí)行完后,先將命令寫入到 AOF 文件的內(nèi)核緩沖區(qū),然后每隔一秒將緩沖區(qū)里的內(nèi)容寫回到硬盤,即每秒執(zhí)行一次 fsync 。
- no: 不由 Redis 控制寫回硬盤的時機(jī),轉(zhuǎn)交給操作系統(tǒng)控制寫回的時機(jī),也就是每次寫操作命令執(zhí)行完后,先將命令寫入到 AOF 文件的內(nèi)核緩沖區(qū),再由操作系統(tǒng)決定何時將緩沖區(qū)內(nèi)容寫回硬盤。即不執(zhí)行 fsync 。
這三種策略各有優(yōu)缺點(diǎn), always 可靠性最強(qiáng)性能較差,no 性能最強(qiáng)可靠性最差,everysec則更為折中。大家可以根據(jù)自己的需要選擇策略。
AOF重寫
AOF日志是一個文件,隨著執(zhí)行的寫操作命令越來越多,文件的大小會越來越大。如果 AOF 文件過大必然會影響性能。因此 Redis 提供了 AOF重寫機(jī)制。
當(dāng) AOF 文件的大小達(dá)到一定閾值時,Redis 會觸發(fā) AOF 重寫過程。這個閾值可以通過配置設(shè)置。
auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb
- auto-aof-rewrite-percentage:指定 AOF 文件大小相對于上一次重寫后大小的增長百分比,當(dāng)超過這個百分比時,Redis 將觸發(fā) AOF 重寫。
- auto-aof-rewrite-min-size: 這個配置項指定了 AOF 文件的最小大小,只有當(dāng) AOF 文件的大小超過這個值時,auto-aof-rewrite-percentage 指定的百分比閾值才會生效。
什么是重寫?AOF 文件記錄了每一個寫操作命令,如果記錄了對同一數(shù)據(jù)的多個操作,實際上只有最后一個操作是有意義的,其他操作都是冗余的。AOF 重寫機(jī)制通過創(chuàng)建一個新的 AOF 文件來解決這個問題,新文件只包含恢復(fù)當(dāng)前數(shù)據(jù)集所需的最小命令集合。
在重寫時 Redis 會通過 fork() 系統(tǒng)調(diào)用創(chuàng)建一個子進(jìn)程,這個子進(jìn)程與父進(jìn)程共享相同的內(nèi)存空間。子進(jìn)程會遍歷 Redis 數(shù)據(jù)庫中的所有鍵,并生成一系列可以恢復(fù)這些數(shù)據(jù)的 Redis 命令,同時將這些命令寫入到一個臨時的 AOF 文件中。
重寫完成后,子進(jìn)程會用新的 AOF 文件替換舊的 AOF 文件,并更新 AOF 文件的文件名。
在重寫過程中,主進(jìn)程并不會阻塞而是繼續(xù)處理客戶端請求,同時將執(zhí)行后的寫命令追加到 「AOF 緩沖區(qū)」與「AOF 重寫緩沖區(qū)」。
當(dāng)重寫完成時,會向主進(jìn)程發(fā)送一條信號,主進(jìn)程收到該信號后,會調(diào)用一個信號處理函數(shù),該函數(shù)會做以下工作:
- 將 AOF 重寫緩沖區(qū)中的所有內(nèi)容追加到新的 AOF 的文件中。
- 新的 AOF 的文件進(jìn)行改名,覆蓋現(xiàn)有的 AOF 文件。
然后主進(jìn)程會繼續(xù)接收命令并執(zhí)行,重寫也就此完成。
AOF優(yōu)缺點(diǎn)
AOF優(yōu)點(diǎn):
- 數(shù)據(jù)安全性高: AOF 記錄了所有寫操作,可以提供更好的數(shù)據(jù)恢復(fù)保證。
- 數(shù)據(jù)完整性: AOF 能夠保證即使在 Redis 異常終止的情況下,也不會丟失任何已持久化的寫操作。
AOF缺點(diǎn):
- 磁盤空間使用: AOF 文件可能會比 RDB 文件大,因為它記錄了所有的寫操作命令。
- 性能影響: 頻繁的磁盤I/O操作可能會影響 Redis 的性能。
- 數(shù)據(jù)恢復(fù)速度: 由于 AOF 文件可能包含大量的命令,數(shù)據(jù)恢復(fù)速度會比 RDB 慢。
混合持久化
我們可以看到RDB與AOF各有優(yōu)缺點(diǎn):RDB 恢復(fù)速度快,AOF 丟失數(shù)據(jù)少?Redis 4.0 引入了一種新的持久化方式,稱為混合持久化,它結(jié)合了 RDB和 AOF持久化的優(yōu)點(diǎn)。
我們可以通過配置文件開啟混合持久化:
aof-use-rdb-preamble yes
當(dāng)開啟了混合持久化時,在 AOF 重寫時,重寫子進(jìn)程會先將與主線程共享的內(nèi)存數(shù)據(jù)以 RDB 方式寫入到 AOF 文件,然后主線程處理的操作命令會被記錄在重寫緩沖區(qū)里,重寫緩沖區(qū)里的增量命令會以 AOF 方式寫入到 AOF 文件,寫入完成后通知主進(jìn)程將新的含有 RDB 格式和 AOF 格式的 AOF 文件替換舊的的 AOF 文件。
當(dāng) Redis 重啟時,它會首先加載 RDB 文件快速恢復(fù)數(shù)據(jù)狀態(tài)。 然后,Redis 會執(zhí)行保存在 AOF 文件中的寫操作命令(這里的內(nèi)容是 Redis 后臺子進(jìn)程重寫 AOF 期間,主線程處理的操作命令。),恢復(fù)到最新的數(shù)據(jù)狀態(tài)。
混合持久化的主要優(yōu)點(diǎn)是結(jié)合了 RDB 和 AOF 的優(yōu)點(diǎn),提供了更快的數(shù)據(jù)恢復(fù)速度和更少的數(shù)據(jù)丟失風(fēng)險。在 AOF 重寫過程中,Redis 確保了數(shù)據(jù)的完整性和一致性,同時優(yōu)化了磁盤空間的使用。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Redis數(shù)據(jù)過期策略的實現(xiàn)詳解
最近項目當(dāng)中遇到一個需求場景,需要清空一些存放在Redis的數(shù)據(jù),本文對Redis的過期機(jī)制簡單的講解一下,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09Redis shake實現(xiàn)可視化監(jiān)控的示例代碼
Redis可視化監(jiān)控是通過監(jiān)控Redis服務(wù)器的各項指標(biāo)和狀態(tài),并將其以可視化的方式展示給用戶,本文給大家介紹了Redis shake實現(xiàn)可視化監(jiān)控,并通過代碼示例講解的非常詳細(xì),需要的朋友可以參考下2024-03-03Redis數(shù)據(jù)導(dǎo)入導(dǎo)出以及數(shù)據(jù)遷移的4種方法詳解
這篇文章主要介紹了Redis數(shù)據(jù)導(dǎo)入導(dǎo)出以及數(shù)據(jù)遷移的4種方法詳解,需要的朋友可以參考下2020-02-02