目錄
1.Redis持久化簡介
2.RDB持久化
? ?2.1 什么是 RDB 持久化?
? ?2.2 觸發(fā)方式
? ?2.3 Redis.conf中配置RDB
? ?2.4 RDB 更深入理解
? ?2.5 RDB優(yōu)缺點
3.AOF持久化
? ?3.1 什么是 AOF 持久化?
? ?3.2 如何實現(xiàn)AOF
? ?3.3 Redis.conf中配置AOF
? ?3.4?深入理解AOF重寫
4.RDB和AOF混合方式(4.0版本)
5.從持久化中恢復數(shù)據(jù)
1.Redis持久化簡介
首先什么是Redis的持久化呢?
Redis作為一個鍵值對內(nèi)存數(shù)據(jù)庫(NoSQL),數(shù)據(jù)都存儲在內(nèi)存當中,在處理客戶端請求時,所有操作都在內(nèi)存當中進行,如下所示:
這樣做有什么問題呢?
存儲在內(nèi)存當中的數(shù)據(jù),只要服務器關機(各種原因引起的),內(nèi)存中的數(shù)據(jù)就會消失,不僅服務器關機會造成數(shù)據(jù)消失,Redis服務器守護進程退出,內(nèi)存中的數(shù)據(jù)也一樣會消失。
對于只把Redis當緩存來用的項目來說,數(shù)據(jù)消失或許問題不大,重新從數(shù)據(jù)源把數(shù)據(jù)加載進來就可以了,但如果直接把用戶提交的業(yè)務數(shù)據(jù)存儲在Redis當中,把Redis作為數(shù)據(jù)庫來使用,在其放存儲重要業(yè)務數(shù)據(jù),那么Redis的內(nèi)存數(shù)據(jù)丟失所造成的影響也許是毀滅性。
為了避免內(nèi)存中數(shù)據(jù)丟失,Redis提供了對持久化的支持,我們可以選擇不同的方式將數(shù)據(jù)從內(nèi)存中保存到硬盤當中,使數(shù)據(jù)可以持久化保存。?
Redis 不同于 Memcached 的很重要一點就是,Redis 支持持久化,而且支持 3 種持久化方式:
- 快照(snapshotting,RDB)
- 只追加文件(append-only file, AOF)
- RDB 和 AOF 的混合持久化(Redis 4.0 新增)
官方文檔地址:Redis persistence | Redis
2.RDB持久化
? ?2.1 什么是 RDB 持久化?
RDB 就是 Redis DataBase 的縮寫,中文名為快照/內(nèi)存快照,RDB持久化是把當前進程數(shù)據(jù)生成快照保存到磁盤上的過程,由于是某一時刻的快照,那么快照中的值要早于或者等于內(nèi)存中的值。
Redis 可以通過創(chuàng)建快照來獲得存儲在內(nèi)存里面的數(shù)據(jù)在 某個時間點 上的副本。Redis 創(chuàng)建快照之后,可以對快照進行備份,可以將快照復制到其他服務器從而創(chuàng)建具有相同數(shù)據(jù)的服務器副本,還可以將快照留在原地以便重啟服務器的時候使用。
? ?2.2 觸發(fā)方式
觸發(fā)RDB持久化的方式有2種,分別是手動觸發(fā)和自動觸發(fā)。
手動觸發(fā)
-
save命令:阻塞當前Redis服務器,直到RDB過程完成為止,對于內(nèi)存 比較大的實例會造成長時間阻塞,線上環(huán)境不建議使用
-
bgsave命令:Redis進程執(zhí)行fork操作創(chuàng)建子進程,RDB持久化過程由子進程負責,完成后自動結束。阻塞只發(fā)生在fork階段,一般時間很短
注意:此處,redis采用的是多進程的方式,來完成的并發(fā)編程,fork是linux系統(tǒng)提供的創(chuàng)建一個子進程的api,如果是其他系統(tǒng),比如windows,創(chuàng)建子進程就不是fork(createProcess)
bgsave流程圖如下所示:
具體流程如下:
- redis客戶端執(zhí)行bgsave命令或者自動觸發(fā)bgsave命令;
- 主進程判斷當前是否已經(jīng)存在正在執(zhí)行的子進程,如果存在,那么主進程直接返回;
- 如果不存在正在執(zhí)行的子進程,那么就fork一個新的子進程進行持久化數(shù)據(jù),fork過程是阻塞的,fork操作完成后主進程即可執(zhí)行其他操作;
- 子進程先將數(shù)據(jù)寫入到臨時的RDB文件中,待快照數(shù)據(jù)寫入完成后再刪除舊的RDB文件,將新的臨時RDB文件改名為dump.rdb文件,自始至終RDB文件是只有一份的;
- 同時發(fā)送信號給主進程,通知主進程rdb持久化完成,主進程更新相關的統(tǒng)計信息。
注意:
Fork創(chuàng)建子進程簡單粗暴,直接把當前的主進程(父進程)復制一份,作為子進程,一旦復制完成,父子進程就是兩個獨立的進程,各自執(zhí)行各自的任務
隨著fork的進行,子進程的這個內(nèi)存里也會存在和剛才父進程中一模一樣的變量,因此,復制出來的這個(子進程)的內(nèi)存中的數(shù)據(jù)就是和(父進程)是一樣的,接下來安排子進程去執(zhí)行“持久化”操作,也就相當與把父進程本體這里的內(nèi)存數(shù)據(jù)給持久化了
存在一個問題:如果當前redis服務器中存儲的數(shù)據(jù)特別多,內(nèi)存消耗很大,此時進行上述的復制操作,是否會有很大的性能開銷?
此時的性能開銷其實是很小的,fork在進行內(nèi)存拷貝的時候,不是直接拷貝所有數(shù)據(jù),而是通過“寫時拷貝”這個機制來完成的
如果子進程中的內(nèi)存數(shù)據(jù)和父進程中的內(nèi)存數(shù)據(jù)完全一樣,此時就不會觸發(fā)真正的拷貝動作,一旦某一方對內(nèi)存數(shù)據(jù)做出了修改,這個時候才會真正觸發(fā)物理內(nèi)存的拷貝,而且在bgsave這個場景下,絕大部分的內(nèi)存數(shù)據(jù),是不需要改變的,因此子進程的“寫時拷貝”并不會觸發(fā)很多次,也就保證了整體的“拷貝時間”是可控的,高效的。
自動觸發(fā)
-
Redis.conf中配置
save m n
,即在m秒內(nèi)有n次修改時,自動觸發(fā)bgsave生成rdb文件; -
主從復制時,從節(jié)點要從主節(jié)點進行全量復制時也會觸發(fā)bgsave操作,生成當時的快照發(fā)送到從節(jié)點;
-
執(zhí)行debug reload命令重新加載Redis時也會觸發(fā)bgsave操作;
-
默認情況下執(zhí)行shutdown命令時,如果沒有開啟AOF持久化,那么也會觸發(fā)bgsave操作;
注意:shutdown命令與service redis-server restart同理,都會自動觸發(fā)
? ?2.3 Redis.conf中配置RDB
快照周期:內(nèi)存快照雖然可以通過技術人員手動執(zhí)行SAVE或BGSAVE命令來進行,但生產(chǎn)環(huán)境下多數(shù)情況都會設置其周期性執(zhí)行條件。
- Redis中默認的周期新設置
# 周期性執(zhí)行條件的設置格式為
save <seconds> <changes>
# 默認的設置為:
save 900 1
save 300 10
save 60 10000
# 以下設置方式為關閉RDB快照功能
save ""
以上三項默認信息設置代表的意義是:
-
如果900秒內(nèi)有1條Key信息發(fā)生變化,則進行快照;
-
如果300秒內(nèi)有10條Key信息發(fā)生變化,則進行快照;
-
如果60秒內(nèi)有10000條Key信息發(fā)生變化,則進行快照。
我們可以按照這個規(guī)則,根據(jù)自己的實際請求壓力進行設置調(diào)整。
-
其它相關配置
# 文件名稱
dbfilename dump.rdb
# 文件保存路徑
dir /home/work/app/redis/data/
# 如果持久化出錯,主進程是否停止寫入
stop-writes-on-bgsave-error yes
# 是否壓縮
rdbcompression yes
# 導入時是否檢查
rdbchecksum yes
dbfilename
:RDB文件在磁盤上的名稱。
dir
:RDB文件的存儲路徑。默認設置為“./”,也就是Redis服務的主目錄。
stop-writes-on-bgsave-error
:上文提到的在快照進行過程中,主進程照樣可以接受客戶端的任何寫操作的特性,是指在快照操作正常的情況下。如果快照操作出現(xiàn)異常(例如操作系統(tǒng)用戶權限不夠、磁盤空間寫滿等等)時,Redis就會禁止寫操作。這個特性的主要目的是使運維人員在第一時間就發(fā)現(xiàn)Redis的運行錯誤,并進行解決。一些特定的場景下,您可能需要對這個特性進行配置,這時就可以調(diào)整這個參數(shù)項。該參數(shù)項默認情況下值為yes,如果要關閉這個特性,指定即使出現(xiàn)快照錯誤Redis一樣允許寫操作,則可以將該值更改為no。
rdbcompression
:該屬性將在字符串類型的數(shù)據(jù)被快照到磁盤文件時,啟用LZF壓縮算法。Redis官方的建議是請保持該選項設置為yes,因為“it’s almost always a win”。
rdbchecksum
:從RDB快照功能的version 5 版本開始,一個64位的CRC冗余校驗編碼會被放置在RDB文件的末尾,以便對整個RDB文件的完整性進行驗證。這個功能大概會多損失10%左右的性能,但獲得了更高的數(shù)據(jù)可靠性。所以如果您的Redis服務需要追求極致的性能,就可以將這個選項設置為no。
? ?2.4 RDB 更深入理解
由于生產(chǎn)環(huán)境中我們?yōu)镽edis開辟的內(nèi)存區(qū)域都比較大(例如6GB),那么將內(nèi)存中的數(shù)據(jù)同步到硬盤的過程可能就會持續(xù)比較長的時間,而實際情況是這段時間Redis服務一般都會收到數(shù)據(jù)寫操作請求。那么如何保證數(shù)據(jù)一致性呢?
RDB中的核心思路是Copy-on-Write,來保證在進行快照操作的這段時間,需要壓縮寫入磁盤上的數(shù)據(jù)在內(nèi)存中不會發(fā)生變化。在正常的快照操作中,一方面Redis主進程會fork一個新的快照子進程專門來做這個事情,這樣保證了Redis服務不會停止對客戶端包括寫請求在內(nèi)的任何響應。另一方面這段時間發(fā)生的數(shù)據(jù)變化會以副本的方式存放在另一個新的內(nèi)存區(qū)域,待快照操作結束后才會同步到原來的內(nèi)存區(qū)域。
舉個例子:如果主線程對這些數(shù)據(jù)也都是讀操作(例如圖中的鍵值對 A),那么,主線程和 bgsave 子進程相互不影響。但是,如果主線程要修改一塊數(shù)據(jù)(例如圖中的鍵值對 C),那么,這塊數(shù)據(jù)就會被復制一份,生成該數(shù)據(jù)的副本。然后,bgsave 子進程會把這個副本數(shù)據(jù)寫入 RDB 文件,而在這個過程中,主線程仍然可以直接修改原來的數(shù)據(jù)。
在進行快照操作的這段時間,如果發(fā)生服務崩潰怎么辦?
很簡單,在沒有將數(shù)據(jù)全部寫入到磁盤前,這次快照操作都不算成功。如果出現(xiàn)了服務崩潰的情況,將以上一次完整的RDB快照文件作為恢復內(nèi)存數(shù)據(jù)的參考。也就是說,在快照操作過程中不能影響上一次的備份數(shù)據(jù)。Redis服務會在磁盤上創(chuàng)建一個臨時文件進行數(shù)據(jù)操作,待操作成功后才會用這個臨時文件替換掉上一次的備份。
如果將RDB文件故意改壞,會發(fā)生什么?
?
? ?2.5 RDB優(yōu)缺點
-
優(yōu)點
- RDB文件是某個時間節(jié)點的快照,默認使用LZF算法進行壓縮,壓縮后的文件體積遠遠小于內(nèi)存大小,適用于備份、全量復制等場景;
- Redis加載RDB文件恢復數(shù)據(jù)要遠遠快于AOF方式;
-
缺點
- RDB方式實時性不夠,無法做到秒級的持久化;
- 每次調(diào)用bgsave都需要fork子進程,fork子進程屬于重量級操作,頻繁執(zhí)行成本較高;
- RDB文件是二進制的,沒有可讀性,AOF文件在了解其結構的情況下可以手動修改或者補全;
- 版本兼容RDB文件問題;
- 還存在一個問題,在兩次生成快照之間,實時的數(shù)據(jù)可能會隨著重啟而丟失
3.AOF持久化
? ?3.1 什么是 AOF 持久化?
與RDB存儲某個時刻的快照不同,AOF持久化方式會記錄客戶端對服務器的每一次寫操作命令,并將這些寫操作以Redis協(xié)議追加保存到以后綴為aof文件末尾,在Redis服務器重啟時,會加載并運行aof文件的命令,以達到恢復數(shù)據(jù)的目的。
與快照持久化相比,AOF 持久化的實時性更好。默認情況下 Redis 沒有開啟 AOF方式(Redis 6.0 之后已經(jīng)默認是開啟了)?
Redis要求高性能,采用寫文件日志有兩方面好處:
- 避免額外的檢查開銷:Redis 在向 AOF 里面記錄日志的時候,并不會先去對這些命令進行語法檢查。所以,如果先記日志再執(zhí)行命令的話,日志中就有可能記錄了錯誤的命令,Redis 在使用日志恢復數(shù)據(jù)時,就可能會出錯。
- 不會阻塞當前的寫操作
但這種方式存在潛在風險:
- 如果命令執(zhí)行完成,寫日志之前宕機了,會丟失數(shù)據(jù)。
- 主線程寫磁盤壓力大,導致寫盤慢,阻塞后續(xù)操作。
? ?3.2 如何實現(xiàn)AOF
AOF 工作流程圖如下:
AOF日志記錄Redis的每個寫命令,步驟分為:命令追加(append)、文件寫入(write)和文件同步(sync)。
-
命令追加 當AOF持久化功能打開了,服務器在執(zhí)行完一個寫命令之后,會以協(xié)議格式將被執(zhí)行的寫命令追加到服務器的 aof_buf 緩沖區(qū)。
-
文件寫入和同步 關于何時將 aof_buf 緩沖區(qū)的內(nèi)容寫入AOF文件中,Redis提供了三種寫回策略:
Always
,同步寫回:每個寫命令執(zhí)行完,立馬同步地將日志寫回磁盤;
Everysec
,每秒寫回:每個寫命令執(zhí)行完,只是先把日志寫到AOF文件的內(nèi)存緩沖區(qū),每隔一秒把緩沖區(qū)中的內(nèi)容寫入磁盤;
No
,操作系統(tǒng)控制的寫回:每個寫命令執(zhí)行完,只是先把日志寫到AOF文件的內(nèi)存緩沖區(qū),由操作系統(tǒng)決定何時將緩沖區(qū)內(nèi)容寫回磁盤。
- 三種寫回策略的優(yōu)缺點
上面的三種寫回策略體現(xiàn)了一個重要原則:trade-off,取舍,指在性能和可靠性保證之間做取舍。
關于AOF的同步策略是涉及到操作系統(tǒng)的 write 函數(shù)和 fsync 函數(shù)的,在《Redis設計與實現(xiàn)》中是這樣說明的:
為了提高文件寫入效率,在現(xiàn)代操作系統(tǒng)中,當用戶調(diào)用write函數(shù),將一些數(shù)據(jù)寫入文件時,操作系統(tǒng)通常會將數(shù)據(jù)暫存到一個內(nèi)存緩沖區(qū)里,當緩沖區(qū)的空間被填滿或超過了指定時限后,才真正將緩沖區(qū)的數(shù)據(jù)寫入到磁盤里。
這樣的操作雖然提高了效率,但也為數(shù)據(jù)寫入帶來了安全問題:如果計算機停機,內(nèi)存緩沖區(qū)中的數(shù)據(jù)會丟失。為此,系統(tǒng)提供了fsync、fdatasync同步函數(shù),可以強制操作系統(tǒng)立刻將緩沖區(qū)中的數(shù)據(jù)寫入到硬盤里,從而確保寫入數(shù)據(jù)的安全性。
?
? ?3.3 Redis.conf中配置AOF
默認情況下,Redis是沒有開啟AOF的,可以通過配置redis.conf文件來開啟AOF持久化,關于AOF的配置如下:
# appendonly參數(shù)開啟AOF持久化
appendonly no
# AOF持久化的文件名,默認是appendonly.aof
appendfilename "appendonly.aof"
# AOF文件的保存位置和RDB文件的位置相同,都是通過dir參數(shù)設置的
dir ./
# 同步策略
# appendfsync always
appendfsync everysec
# appendfsync no
# aof重寫期間是否同步
no-appendfsync-on-rewrite no
# 重寫觸發(fā)配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 加載aof出錯如何處理
aof-load-truncated yes
# 文件重寫策略
aof-rewrite-incremental-fsync yes
以下是Redis中關于AOF的主要配置信息:
appendonly
:默認情況下AOF功能是關閉的,將該選項改為yes以便打開Redis的AOF功能。
appendfilename
:這個參數(shù)項很好理解了,就是AOF文件的名字。
appendfsync
:這個參數(shù)項是AOF功能最重要的設置項之一,主要用于設置“真正執(zhí)行”操作命令向AOF文件中同步的策略。
什么叫“真正執(zhí)行”呢?還記得Linux操作系統(tǒng)對磁盤設備的操作方式嗎? 為了保證操作系統(tǒng)中I/O隊列的操作效率,應用程序提交的I/O操作請求一般是被放置在linux Page Cache中的,然后再由Linux操作系統(tǒng)中的策略自行決定正在寫到磁盤上的時機。而Redis中有一個fsync()函數(shù),可以將Page Cache中待寫的數(shù)據(jù)真正寫入到物理設備上,而缺點是頻繁調(diào)用這個fsync()函數(shù)干預操作系統(tǒng)的既定策略,可能導致I/O卡頓的現(xiàn)象頻繁 。
appendfsync參數(shù)項可以設置三個值,分別是:always、everysec、no,默認的值為everysec。
no-appendfsync-on-rewrite
:always和everysec的設置會使真正的I/O操作高頻度的出現(xiàn),甚至會出現(xiàn)長時間的卡頓情況,這個問題出現(xiàn)在操作系統(tǒng)層面上,所有靠工作在操作系統(tǒng)之上的Redis是沒法解決的。為了盡量緩解這個情況,Redis提供了這個設置項,保證在完成fsync函數(shù)調(diào)用時,不會將這段時間內(nèi)發(fā)生的命令操作放入操作系統(tǒng)的Page Cache(這段時間Redis還在接受客戶端的各種寫操作命令)。
auto-aof-rewrite-percentage
:更多時候我們需要依靠Redis中對AOF文件的自動重寫策略。Redis中對觸發(fā)自動重寫AOF文件的操作提供了兩個設置:auto-aof-rewrite-percentage表示如果當前AOF文件的大小超過了上次重寫后AOF文件的百分之多少后,就再次開始重寫AOF文件。例如該參數(shù)值的默認設置值為100,意思就是如果AOF文件的大小超過上次AOF文件重寫后的1倍,就啟動重寫操作。
auto-aof-rewrite-min-size
:參考auto-aof-rewrite-percentage選項的介紹,auto-aof-rewrite-min-size設置項表示啟動AOF文件重寫操作的AOF文件最小大小。如果AOF文件大小低于這個值,則不會觸發(fā)重寫操作。注意,auto-aof-rewrite-percentage和auto-aof-rewrite-min-size只是用來控制Redis中自動對AOF文件進行重寫的情況,如果是技術人員手動調(diào)用“BGREWRITEAOF”命令,則不受這兩個限制條件左右。
? ?3.4?深入理解AOF重寫
AOF會記錄每個寫命令到AOF文件,隨著時間越來越長,AOF文件會變得越來越大。如果不加以控制,會對Redis服務器,甚至對操作系統(tǒng)造成影響,而且AOF文件越大,數(shù)據(jù)恢復也越慢。為了解決AOF文件體積膨脹的問題,Redis提供AOF文件重寫機制來對AOF文件進行“瘦身”。
- 圖例解釋AOF重寫
Redis通過創(chuàng)建一個新的AOF文件來替換現(xiàn)有的AOF,新舊兩個AOF文件保存的數(shù)據(jù)相同,但新AOF文件沒有了冗余命令。
?關于AOF重寫的流程看下圖:
4.RDB和AOF混合方式(4.0版本)
Redis 4.0 中提出了一個混合使用 AOF 日志和內(nèi)存快照的方法。簡單來說,內(nèi)存快照以一定的頻率執(zhí)行,在兩次快照之間,使用 AOF 日志記錄這期間的所有命令操作。
這樣一來,快照不用很頻繁地執(zhí)行,這就避免了頻繁 fork 對主線程的影響。而且,AOF 日志也只用記錄兩次快照間的操作,也就是說,不需要記錄所有操作了,因此,就不會出現(xiàn)文件過大的情況了,也可以避免重寫開銷。
如下圖所示,T1 和 T2 時刻的修改,用 AOF 日志記錄,等到第二次做全量快照時,就可以清空 AOF 日志,因為此時的修改都已經(jīng)記錄到快照中了,恢復時就不再用日志了。
這個方法既能享受到 RDB 文件快速恢復的好處,又能享受到 AOF 只記錄操作命令的簡單優(yōu)勢, 實際環(huán)境中用的很多。?
5.從持久化中恢復數(shù)據(jù)
數(shù)據(jù)的備份、持久化做完了,我們?nèi)绾螐倪@些持久化文件中恢復數(shù)據(jù)呢?如果一臺服務器上有既有RDB文件,又有AOF文件,該加載誰呢?
其實想要從這些文件中恢復數(shù)據(jù),只需要重新啟動Redis即可。我們還是通過圖來了解這個流程:
文章來源:http://www.zghlxwxcb.cn/news/detail-655079.html
- Redis重啟時判斷是否開啟AOF,如果開啟了AOF,那么就優(yōu)先加載AOF文件;
- 如果AOF存在,那么就去加載AOF文件,加載成功的話Redis重啟成功,如果AOF文件加載失敗,那么會打印日志表示啟動失敗,此時可以去修復AOF文件后重新啟動;
- 若AOF文件不存在,那么Redis就會轉而去加載RDB文件,如果RDB文件不存在,Redis直接啟動成功;
- 如果RDB文件存在就會去加載RDB文件恢復數(shù)據(jù),如加載失敗則打印日志提示啟動失敗,如加載成功,那么Redis重啟成功,且使用RDB文件恢復數(shù)據(jù);
那么為什么會優(yōu)先加載AOF呢?因為AOF保存的數(shù)據(jù)更完整,通過上面的分析我們知道AOF基本上最多損失1s的數(shù)據(jù)。文章來源地址http://www.zghlxwxcb.cn/news/detail-655079.html
到了這里,關于Redis持久化:RDB和AOF機制詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!