您好,登錄后才能下訂單哦!
小編給大家分享一下Redis中持久化機制是怎么樣的,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!
為什么要持久化
如果Redis再次訪問時,發現Redis的數據是空的,就會形成緩存穿透。更重要的是,因為Redis的數據是空的,所以客戶端想要訪問的key都沒有,就會造成大量的請求就會瞬間打到數據庫上,造成緩存雪崩(少量的key是穿透,大量的key是雪崩)。
這個時候,數據庫可能就掛掉。而又無法保證redis不宕機,所以需要當redis宕機后,迅速將里里面的內容恢復出來。因此需要做一個持久化。持久化是為了恢復數據用的,而不是存儲數據用的。
RDB
RDB(Redis DataBase),是Redis默認的存儲方式,RDB方式是通過快照(snapshotting)完成的。
觸發快照的方式
符合自定義配置的快照規則
save 900 1 # 表示15分鐘(900秒鐘)內至少1個鍵被更改則進行快照。
save 300 10 # 表示5分鐘(300秒)內至少10個鍵被更改則進行快照。
save 60 10000 # 表示1分鐘內至少10000個鍵被更改則進行快
N秒內數據集至少有M個改動”這一條件被滿足時,自動保存一次數據集。
執行save或者bgsave命令
執行命令save或bgsave可以生成dump.rdb文件,每次命令執行都會將所有redis內存快照到一個新的rdb文件里,并覆蓋原有rdb快照文件。
save與bgsave對比:
命令 | save | bgsave |
---|---|---|
IO類型 | 同步 | 異步 |
是否阻塞redis其它命令 | 是 | 否(在生成子進程執行調用fork函數時會有短暫阻塞) |
復雜度 | O(n) | O(n) |
優點 | 不會消耗額外內存 | 不阻塞客戶端命令 |
缺點 | 阻塞客戶端命令 | 需要fork子進程,消耗內存 |
配置自動生成rdb文件后臺使用的是bgsave方式。
執行flushall命令
flushall
清空Redis之前,保存當前Redis快照
執行主從復制操作 (第一次)
第一次主從復制時需要生成rdb文件,會保存當前Redis快照
RDB執行流程
流程分析
父進程fork子進程后,繼續工作。
子進程發送信號給父進程表示完成,父進程更新統計信息。
子進程創建RDB文件,根據父進程內存快照生成臨時快照文件,完成后對原有文件進行原子替換。(RDB始終完整)
父進程fork后,bgsave命令返回”Background saving started”信息并不再阻塞父進程,并可以響應其他命令。
父進程執行fork(調用操作系統函數復制主進程)操作創建子進程,這個過程中父進程是阻塞的,Redis不能執行來自客戶端的任何命令。
Redis父進程首先判斷:當前是否在執行save或bgsave/bgrewriteaof(aof文件重寫命令)的子進程,如果在執行則bgsave命令直接返回。
RDB文件結構
1、頭部5字節固定為“REDIS”字符串
2、4字節“RDB”版本號(不是Redis版本號),當前為9,填充后為0009
3、輔助字段,以key-value的形式
4、存儲數據庫號碼
5、字典大小
6、過期key
7、主要數據,以key-value的形式存儲
8、結束標志
9、校驗和,就是看文件是否損壞,或者是否被修改
RDB的優缺點
優點
RDB是二進制壓縮文件,占用空間小,便于傳輸(傳給slaver)
主進程fork子進程,可以最大化Redis性能,主進程不能太大,復制過程中主進程阻塞
缺點
不保證數據完整性,會丟失最后一次快照以后更改的所有數據
AOF
AOF(append only file)是Redis的另一種持久化方式。Redis默認情況下是不開啟的。開啟AOF持久化后,Redis將所有對數據庫進行過寫入的命令(及其參數)(RESP)記錄到AOF文件,以此達到記錄數據庫狀態的目的,
這樣當Redis重啟后只要按順序回放這些命令就會恢復到原始狀態了。AOF會記錄過程,RDB只管結果
AOF持久化實現
配置 redis.conf
# 可以通過修改redis.conf配置文件中的appendonly參數開啟 appendonly yes # AOF文件的保存位置和RDB文件的位置相同,都是通過dir參數設置的。 dir ./ # 默認的文件名是appendonly.aof,可以通過appendfilename參數修改 appendfilename appendonly.aof
AOF原理
AOF文件中存儲的是redis的命令,同步命令到 AOF 文件的整個過程可以分為三個階段:
命令傳播:Redis將執行完的命令、命令的參數、命令的參數個數等信息發送到 AOF 程序中。
緩存追加:AOF程序根據接收到的命令數據,將命令轉換為網絡通訊協議的格式,然后將協議內容追加 到服務器的AOF緩存中。
文件寫入和保存:AOF 緩存中的內容被寫入到 AOF 文件末尾,如果設定的 AOF 保存條件被滿足的話, fsync函數或者fdatasync 函數會被調用,將寫入的內容真正地保存到磁盤中。
命令傳播
當一個Redis客戶端需要執行命令時,它通過網絡連接,將協議文本發送給Redis服務器。服務器在接到客戶端的請求之后,它會根據協議文本的內容,選擇適當的命令函數,并將各個參數從字符串文本轉換為Redis 字符串對象(StringObject)。每當命令函數成功執行之后,命令參數都會被傳播到AOF程序。
緩存追加
當命令被傳播到AOF程序之后,程序會根據命令以及命令的參數,將命令從字符串對象轉換回原來的協議文本。協議文本生成之后,它會被追加到redis.h/redisServer結構的aof_buf 末尾。
redisServer結構維持著Redis服務器的狀態,aof_buf域則保存著所有等待寫入到AOF 文件的協議文本(RESP)
文件寫入和保存
每當服務器常規任務函數被執行、或者事件處理器被執行時,aof.c/flushAppendOnlyFile 函數都會被調用,這個函數執行以下兩個工作:
WRITE:根據條件將aof_buf中的緩存寫入到AOF文件。
SAVE:根據條件調用fsync或 fdatasync函數將AOF文件保存到磁盤中。
AOF保存模式
Redis 目前支持三種 AOF 保存模式,它們分別是:
AOF_FSYNC_NO :不保存。
AOF_FSYNC_EVERYSEC :每一秒鐘保存一次。(默認)
AOF_FSYNC_ALWAYS :每執行一個命令保存一次。(不推薦)
AOF_FSYNC_NO
從不fsync,將數據交給操作系統來處理。更快,也更不安全的選擇。
SAVE只會在以下任意一種情況中被執行:
Redis被關閉
AOF功能被關閉
系統的寫緩存被刷新(可能是緩存已經被寫滿,或者定期保存操作被執行)
這三種情況下的SAVE操作都會引起Redis主進程阻塞。
AOF_FSYNC_EVERYSEC
SAVE原則上每隔一秒鐘就會執行一次,因為SAVE操作是由后臺子線程(fork)調用的, 所以它不會引起服務器主進程阻塞,并且在故障時只會丟失1秒鐘的數據。
AOF_FSYNC_ALWAYS
每次執行完一個命令之后,WRITE和SAVE都會被執行。每次有新命令追加到AOF文件時就執行一次fsync,非常慢,也非常安全。
因為SAVE是由Redis主進程執行的,所以在SAVE執行期間,主進程會被阻塞,不能接受命令請求。
AOF保存模式對性能和安全性的影響
三種模式的比較
AOF重寫
AOF記錄數據的變化過程,越來越大,需要重寫“瘦身”
Redis可以在AOF體積變得過大時,自動地在后臺(Fork子進程)對AOF進行重寫。
重寫后的新AOF文件包含了恢復當前數據集所需的最小命令集合。
所謂的“重寫”其實是一個有歧義的詞語,實際上,AOF重寫并不需要對原有的AOF文件進行任何寫入和讀取,它針對的是數據庫中鍵的當前值。
舉例說明
set s1 11 set s1 22 set s1 33 lpush list1 1 2 3 lpush list1 4 5 6
AOF重寫后
set s1 33 lpush list1 1 2 3 4 5 6
Redis不希望AOF重寫造成服務器無法處理請求,所以Redis決定將AOF重寫程序放到(后臺)子進程里執行,
1、子進程進行AOF重寫期間,主進程可以繼續處理命令請求。
2、子進程帶有主進程的數據副本,使用子進程而不是線程,可以在避免鎖的情況下,保證數據的安全性。
不過,使用子進程也有一個問題需要解決:因為子進程在進行AOF重寫期間,主進程還需要繼續處理命令,而新的命令可能對現有的數據進行修改,這會讓當前數據庫的數據和重寫后的AOF文件中的數據不一致。
為了解決這個問題,Redis增加了一個AOF重寫緩存,這個緩存在fork出子進程之后開始啟用,Redis主進程在接到新的寫命令之后,除了會將這個寫命令的協議內容追加到現有的AOF文件之外,還會追加到這個緩存中。
重寫過程分析
Redis在創建新AOF文件的過程中,會繼續將命令追加到現有的AOF文件里面,即使重寫過程中發生停機,現有的AOF文件也不會丟失。而一旦新AOF文件創建完畢,Redis就會從舊AOF文件切換到新AOF文件,并開始對新AOF文件進行追加操作。
當子進程在執行AOF重寫時,主進程需要執行以下三個工作:
處理命令請求。
將寫命令追加到現有的AOF文件中。
將寫命令追加到AOF重寫緩存中
。這樣一來可以保證:現有的AOF功能會繼續執行,即使在AOF重寫期間發生停機,也不會有任何數據丟失。所有對數據庫進行修改的命令都會被記錄到AOF重寫緩存中。
當子進程完成AOF重寫之后,它會向父進程發送一個完成信號,父進程在接到完成信號之后,會調用一個信號處理函數,并完成以下工作:
將AOF重寫緩存中的內容全部寫入到新AOF文件中。
對新的AOF文件進行改名,覆蓋原有的AOF文件。
Redis數據庫里的+AOF重寫過程中的命令------->新的AOF文件---->覆蓋老的當步驟1執行完畢之后,現有AOF文件、新AOF文件和數據庫三者的狀態就完全一致了。
當步驟2執行完畢之后,程序就完成了新舊兩個AOF文件的交替。這個信號處理函數執行完畢之后,主進程就可以繼續像往常一樣接受命令請求了
。在整個AOF后臺重寫過程中,只有最后的寫入緩存和改名操作會造成主進程阻塞,在其他時候,AOF后臺重寫都不會對主進程造成阻塞,這將AOF重寫對性能造成的影響降到了最低。
AOF重寫觸發方式
1、配置觸發
#表示當前aof文件大小超過上一次aof文件大小的百分之多少的時候會進行重寫。如果之前沒有重寫過,以啟動時aof文件大小為準 auto-aof-rewrite-percentage 100 #限制允許重寫最小aof文件大小,也就是文件大小小于64mb的時候,不需要進行優化 auto-aof-rewrite-min-size 64mb
2、執行bgrewriteaof命令
127.0.0.1:6379>bgrewriteaof‘ Backgroundappendonlyfilerewritingstarted
AOF重寫總結
混合持久化
RDB和AOF各有優缺點,Redis 4.0開始支持rdb和aof的混合持久化。
如果把混合持久化打開,aofrewrite的時候就直接把rdb的內容寫到aof文件開頭。
RDB的頭+AOF的身體---->appendonly.aof
開啟混合持久化
aof-use-rdb-preambleyes
AOF文件的載入與數據還原
如果開啟了混合持久化,AOF在重寫時,不再是單純將內存數據轉換為RESP命令寫入AOF文件,而是將重寫這一刻之前的內存做RDB快照處理,并且將RDB快照內容和增量的AOF修改內存數據的命令存在一起,都寫入新的AOF文件,新的文件一開始不叫appendonly.aof,等到重寫完新的AOF文件才會進行改名,覆蓋原有的AOF文件,完成新舊兩個AOF文件的替換。
于是在Redis重啟的時候,可以先加載RDB的內容,然后再重放增量AOF日志就可以完全替代之前的AOF全量文件重放,因此重啟效率大幅得到提升。
1、創建一個不帶網絡連接的偽客戶端(fake client)
因為Redis的命令只能在客戶端上下文中執行,而載入AOF文件時所使用的命令直接來源于AOF文件而不是網絡連接,所以服務器使用了一個沒有網絡連接的偽客戶端來執行AOF文件保存的寫命令,偽客戶端執行命令的效果和帶網絡連接的客戶端執行命令的效果完全一樣
2、從AOF文件中分析并讀取出一條寫命令
3、使用偽客戶端執行被讀出的寫命令
4、一直執行步驟2和步驟3,直到AOF文件中的所有寫命令都被處理完畢為止
Redis數據備份策略
1.寫crontab定時調度腳本,每小時都copy一份rdb或aof的備份到一個目錄中去,僅僅保留最近48小時的備份
2.每天都保留一份當日的數據備份到一個目錄中去,可以保留最近1個月的備份
3.每次copy備份的時候,都把太舊的備份給刪了
4.每天晚上將當前機器上的備份復制一份到其他機器上,以防機器損壞
RDB和AOF對比
1、RDB存某個時刻的數據快照,采用二進制壓縮存儲,AOF存操作命令,采用文本存儲(混合)
2、RDB性能高、AOF性能較低
3、RDB在配置觸發狀態會丟失最后一次快照以后更改的所有數據,AOF設置為每秒保存一次,則最多丟2秒的數據
4、Redis以主服務器模式運行,RDB不會保存過期鍵值對數據,Redis以從服務器模式運行,RDB會保存過期鍵值對,當主服務器向從服務器同步時,再清空過期鍵值對。AOF寫入文件時,對過期的key會追加一條del命令,當執行AOF重寫時,會忽略過期key和del命令。
看完了這篇文章,相信你對“Redis中持久化機制是怎么樣的”有了一定的了解,如果想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。