淺談:Redis持久化機制(一)RDB篇
眾所周知,redis是一款性能極高,基於內存的鍵值對NoSql數據庫,官方顯示,它的讀效率可達到11萬次每秒,寫效率能達到8萬次每秒,因為它基於內存以及存讀效率高的特性,在市場上的應用中一般都把它作為緩存來使用,同時這也意味着它不能大量的無限制的填充數據,否則容易內存填滿,導致redis會向硬盤申請虛擬內存,造成內存和外存的不斷I/O,致使效率低下,甚至引起宕機,那么問題來了,既然只是當做緩存而不是為了永久存儲數據,redis為什么要做持久化呢?這樣做有什么意義呢?
1.為什么要做持久化
- 第一點要明確,redis作為內存數據庫,宕機后就會發生數據消失,之所以要去做持久化只是為了能在重啟之后快速的恢復數據,而不是存儲數據;redis的持久化並不能夠保證數據的完整性.
- 當然,如果要把redis當做DB用,DB數據要完整,所以需要一個完整的數據源(比如mysql),當啟動時將數據源的數據全部加載到redis里面,這只適用於數據量小的不易改變的,比如:字典庫。像mysql那樣大量的存儲數據是行不通的。
2.RDB(redis database)
說完redis持久化的原因,我們再詳聊一下redis做持久化的第一種方式RDB,這種方式也是redis默認的一種持久化方式,默認是開啟的。
從字面上來看,RDB也就是redis database,翻譯成中文就是redis 數據庫,也就是說這種持久化方式就是像數據庫一樣存儲了數據,當然事實上也是這樣的,RDB方式是通過存儲快照數據來完成的,既然是快照數據,那就是說明這種方式只關注了某一刻緩存的數據狀態,關注的是那一刻數據是什么,它並沒有去記錄這個數據變更的一系列過程。也就是說,RDB持久化方式關注的是數據存儲的結果,而非是數據存儲的過程。
另外,既然是快照數據,redis又要保證性能,因此要明白RDB持久化時肯定不會是實時的,肯定是隔一段時間觸發一次,否則的話redis作為一個單線程處理的服務,光顧着去持久化數據了,怎么還有時間處理來自客戶端的請求訪問,這也就說明了由於有時間間隔,redis的RDB方式的持久化會丟失最后一次持久化后的數據,這也就表明了redis的持久化沒有辦法保證數據的完整性。
2.1 觸發快照的方式
- 配置參數定期執行(在redis.conf中配置:save 多少秒內 數據變了多少)
save "" # 不使用RDB存儲 不能主從
save 900 1 # 表示15分鍾(900秒鍾)內至少1個鍵被更改則進行快照。
save 300 10 # 表示5分鍾(300秒)內至少10個鍵被更改則進行快照。
save 60 10000 # 表示1分鍾內至少10000個鍵被更改則進行快照。
-
命令顯式觸發(save或者bgsave命令)
127.0.0.1:6379> bgsave Background saving started
2.2 RDB執行流程

1.redis父進程首先判斷,當前是否正在執行save,如果正在執行,則先返回。
2.父進程fork()復制出子進程,在這個過程中父進程是阻塞的,不再處理redis接收到的其他命令。當父進程fork結束,又可以重新處理工作。
3.子進程創建RDB文件,根據父進程的內存快照生成臨時快照文件,完成后對原有的文件進行替換。始終保持RDB文件的完整性。
4.子進程生成RDB文件完成后,就響應信息給父進程,父進程更新統計信息。
2.3 RDB文件結構

1、頭部5字節固定為“REDIS”字符串
2、4字節“RDB”版本號(不是Redis版本號),當前為9,填充后為0009
3、輔助字段,以key-value的形式
| 字段名 | 字段值 | 字段名 | 字段值 |
|---|---|---|---|
| redis-ver | 5.0.5 | aof-preamble | 是否開啟aof |
| redis-bits | 64/32 | repl-stream-db | 主從復制 |
| ctime | 當前時間戳 | repl-id | 主從復制 |
| used-mem | 使用內存 | repl-offset | 主從復制 |
4、存儲數據庫號碼
5、字典大小6、過期key
7、主要數據,以key-value的形式存儲
8、結束標志
9、校驗和,就是看文件是否損壞,或者是否被修改。
2.4 RDB的優缺點
優點:
- RDB是二進制壓縮文件,占用空間小,便於傳輸。(做主從復制時傳遞給slaver效率也很高)
- 通過主進程fork復制子進程,由子進程完成持久化的方式,這樣可以最大化的保證redis的性能。但是前提條件是redis的數據量不能太大,否則fork的過程太長,容易造成阻塞。
缺點:
- 不能保證數據的完整性,會丟失最后一次fork之后的數據。例如,redis進行持久化的操作是1分鍾一次,當上次持久化完成后的30秒內,新添加了5000個數據,那么redis發生宕機然后重新恢復時,那30秒的數據會丟失。
