從上篇 RedisTemplate 可沒你想的那麼簡單 完結後,整個 Redis 的客戶端相關的就弄完了,主要是
Jedis
、Lettuce
、RedisTemplate
三篇。有不熟悉的好哥哥能夠去個人文章那裏翻翻,說不定就會有不同的收穫。今天的這篇的話是關於 Redis 持久化相關的第一篇,後續應該會有幾篇關於持久化的,好哥哥們好好看,主要是要動手操做起來。固然若是隻是爲了應付面試的話能夠大概的看看,可是仍是建議這一塊相關的東西系統的看看。看完記得點贊加關注喲。
面試
Redis 系列第一篇 初識 Redis 中就有提到說 Redis 是一個基於內存的非關係性數據庫。那所謂內存數據庫,就是將數據庫中的內容保存在內存中,這與傳統的MySQL
,Oracle
等關係型數據庫直接將內容保存到硬盤中相比,內存數據庫的讀寫效率比傳統數據庫要快的多(內存的讀寫效率遠遠大於硬盤的讀寫效率)。可是保存在內存中也隨之帶來了一個缺點,一旦斷電或者宕機,那麼內存數據庫中的數據將會所有丟失。
爲了解決這個缺點,Redis 提供了將內存數據持久化到硬盤,以及用持久化文件來恢復數據庫數據的功能。Redis 支持兩種形式的持久化,一種是RDB
快照(snapshotting),另一種是AOF
(append-only-file)。redis
RDB
持久化是把當前進程數據生成快照保存到硬盤的過程。可以在指定時間間隔內對數據進行快照存儲,默認狀況下,Redis 將數據快照保存在dump.rdb
這個二進制的文件中。觸發RDB
持久化過程分爲手動觸發和自動觸發。算法
上面有提到觸發分爲手動觸發和自動觸發。手動觸發又分紅了兩種方式,第一種使用save
,第二種使用bgsave
。shell
save
會阻塞當前 Redis 服務器,直到RDB
過程完成爲止,對於內存比較大的實例會形成長時間阻塞,線上環境不建議使用。命令以下:數據庫
127.0.0.1:6379> save
OK
複製代碼
上面提到了就是save
是一個阻塞操做。假設在生產環境中使用這個命令,若是數據量夠大,那麼會使 Redis 服務器阻塞的時間很是長,致使 Redis 服務的不可用。bgsave
就是用來解決這個問題的,bgsave
執行時,Redis 進程會執行fork
操做建立子進程,RDB 持久化過程由子進程負責,完成後自動結束。阻塞只發生在 fork 階段,通常時間很短。數組
127.0.0.1:6379> bgsave
Background saving started
複製代碼
整個過程以下:
服務器
命令 | save | bgsave |
---|---|---|
類型 | 同步 | 異步 |
是否阻塞 | 是 | 只有在 fork 是阻塞的 |
優勢 | 沒有額外的內存消耗 | 不會阻塞服務器 |
缺點 | 阻塞服務器 | 須要 fork 建立子進程,額外消耗內存 |
除了執行命令手動觸發以外,Redis 內部還存在自動觸發RDB
的持久化機制。觸發的邏輯是 Redis 在 N 秒內有 M 個鍵被改動,好哥哥們能夠經過修改配置文件來實現對RDB
的自動觸發。默認配置以下:markdown
## 表示 900 秒內若是至少有 1 個 key 的值變化,則觸發
save 900 1
## 表示300 秒內若是至少有 10 個 key 的值變化,則觸發
save 300 10
## 表示60 秒內若是至少有 10000 個 key 的值變化,則觸發
save 60 10000
複製代碼
其餘 RDB 相關配置:網絡
## bgsave寫入錯誤是否中止寫入
stop-writes-on-bgsave-error yes
## 是否對rdb文件使用壓縮格式
rdbcompression yes
## 是否對rdb文件校驗
rdbchecksum yes
## rdb持久化名稱
dbfilename dump.rdb
## rdb持久化存放目錄
dir ./
複製代碼
Redis 服務器維護了一個狀態結構,其中包括save條件的數組(saveparams)
、計數器(dirty)
、上次保存時間(lastsave)
。前面咱們在 redis.conf
配置文件中進行了關於save
的配置,解析成條件的數組後就是下面的樣子:
當服務器成功執行一次修改操做,那麼計數器(dirty)
就會加 1。而lastsave
屬性記錄上一次執行save
或bgsave
的時間,Redis 服務器還有一個週期性操做函數 severCron
,默認每隔 100 毫秒就會執行一次,該函數會遍歷並檢查 saveparams
數組中的全部保存條件,只要有一個條件被知足,那麼就會執行 bgsave
命令。 執行完成以後,計數器(dirty)
更新爲 0 ,lastsave
也更新爲執行命令的完成時間。app
假設哪天有哪位好哥哥執行了FLUSHALL
命令(千萬別再生產上使用這個命令哦),把全部數據都清了,這時不要慌將備份文件dump.rdb
(前提是你的快照生成的時機在FLUSHALL
以前) 移動到 Redis 安裝目錄並啓動服務便可,Redis 就會自動加載文件數據至內存了。Redis 服務器在載入 RDB 文件期間,會一直處於阻塞狀態,直到載入工做完成爲止。獲取 Redis 的安裝目錄可使用下面的命令。
config get dir
複製代碼
看這個文件我已經快瞎了,因此我在解釋前面都加了行號(夠貼心了吧,這還不點贊加關注嗎)。
➜ go-redis-parser od -A x -t x1c -v ./teststub/dumpV9.rdb
000000 52 45 44 49 53 30 30 30 39 fa 09 72 65 64 69 73
R E D I S 0 0 0 9 372 \t r e d i s
000010 2d 76 65 72 05 35 2e 30 2e 35 fa 0a 72 65 64 69
- v e r 005 5 . 0 . 5 372 \n r e d i
000020 73 2d 62 69 74 73 c0 40 fa 05 63 74 69 6d 65 c2
s - b i t s 300 @ 372 005 c t i m e 302
000030 71 8a 8d 5d fa 08 75 73 65 64 2d 6d 65 6d c2 30
q 212 215 ] 372 \b u s e d - m e m 302 0
000040 e0 0f 00 fa 0c 61 6f 66 2d 70 72 65 61 6d 62 6c
340 017 \0 372 \f a o f - p r e a m b l
000050 65 c0 00 fe 00 fb 06 00 f9 00 00 01 73 01 61 f9
e 300 \0 376 \0 373 006 \0 371 \0 \0 001 s 001 a 371
000060 03 0e 02 6c 69 01 11 11 00 00 00 0d 00 00 00 02
003 016 002 l i 001 021 021 \0 \0 \0 \r \0 \0 \0 002
000070 00 00 01 61 03 01 62 ff f9 00 02 03 73 65 74 02
\0 \0 001 a 003 001 b 377 371 \0 002 003 s e t 002
000080 01 62 01 61 f9 00 0f 06 73 74 72 65 61 6d 01 10
001 b 001 a 371 \0 017 006 s t r e a m 001 020
000090 00 00 01 6d 70 b5 4a 7e 00 00 00 00 00 00 00 00
\0 \0 001 m p 265 J ~ \0 \0 \0 \0 \0 \0 \0 \0
0000a0 40 52 52 00 00 00 18 00 03 01 00 01 02 01 84 6e
@ R R \0 \0 \0 030 \0 003 001 \0 001 002 001 204 n
0000b0 61 6d 65 05 83 61 67 65 04 00 01 02 01 00 01 00
a m e 005 203 a g e 004 \0 001 002 001 \0 001 \0
0000c0 01 87 4c 61 6d 62 65 72 74 08 1d 01 05 01 02 01
001 207 L a m b e r t \b 035 001 005 001 002 001
0000d0 f2 33 8c 00 04 00 01 84 4a 61 63 6b 05 1a 01 05
362 3 214 \0 004 \0 001 204 J a c k 005 032 001 005
0000e0 01 02 01 f2 9c ad 00 04 00 01 83 54 6f 6d 04 1e
001 002 001 362 234 255 \0 004 \0 001 203 T o m 004 036
0000f0 01 05 01 ff 03 81 00 00 01 6d 70 b5 f8 1a 00 01
001 005 001 377 003 201 \0 \0 001 m p 265 370 032 \0 001
000100 05 67 72 6f 75 70 00 00 00 00 f9 00 0c 04 7a 73
005 g r o u p \0 \0 \0 \0 371 \0 \f 004 z s
000110 65 74 15 15 00 00 00 12 00 00 00 04 00 00 01 61
e t 025 025 \0 \0 \0 022 \0 \0 \0 004 \0 \0 001 a
000120 03 f2 02 01 62 03 f3 ff f9 03 0d 01 68 11 11 00
003 362 002 001 b 003 363 377 371 003 \r 001 h 021 021 \0
000130 00 00 0d 00 00 00 02 00 00 01 61 03 01 61 ff ff
\0 \0 \r \0 \0 \0 002 \0 \0 001 a 003 001 a 377 377
000140 0e e0 f7 31 2f 37 16 df
016 340 367 1 / 7 026 337
000148
複製代碼
這是一個 version 9
的 RDB
文件,主要表達內容以下:
在第 000000
前 9 個字節是一個魔數,5 個字節 REDIS 和 4 個字節的版本號 0009。
通用字符串字段,用於向 RDB
添加狀態,Version 7
加入的,向後兼容。AUX
字段由鍵和值兩個字符串組成。主要有如下字段:
000050
的 fe(0xfe)
,fb(0xfb)
是 10 進制的 254 和 251,在 RDB 中國分別對應SELECT_DB
和RESIZE_DB
。 每個 SELECTDB
後都會緊跟着RESIZEDB
,後者表示的是當前數據庫hashtable
鍵大小的提示,每次切換數據庫時提早讀到,避免沒必要要的rehash
。
這裏的話就列舉基礎數據類型
000050
的 00(0x00)
是 10 進制的 0,表示String
類型的對象,01 指key
是一個字節長度:s
, value
也是一個字節長度:a
。
000060
的0e(0x0e)
是 10 進制的 14,表示List
類型的對象。 2 個字節長度的key
是li
,接下來分別是一個長度的items
:a
和 b
000070
的002
,表示 Set 類型對象,3 個長度 set
,兩個members
:a
和 b
000100
的0c
是 10 進制的 12,以ziplist
結構存儲的Sortedse
t 類型,4 個長度的key:zset
,接下來的 4 表示:4 個元素,zset
會將member
和score
一塊兒保存,因此,就是 2 組members
;分別是:{memeber:"a",score:1}
、{member:"b",score:2}
。
000120
的0d(13)
是RDB_TYPE_HASH_ZIPLIST
,表示是ziplist
存儲的hash
類型數據,1 個長度的 key:h
。 key
後面的 2,存着 hash
結構的 field
和 value
;在 field
和 value
前面的 1,分別是指各自的長度,都是 a
。
000130
的ff(255) EOF
,在全部數據寫完結束後,會以一個EOF
結尾。
從Version 5
開始,若是在配置文件中開啓rdbchecksum yes
(上面解釋過這個配置),會在RDB
文件的結尾處,用 8 個字節記錄,經過CRC64
算法計算的整個文件內容的校驗和。
RDB
文件保存在dir
配置指定的目錄下,文件名經過dbfilename
配置指定。能夠經過執行config set dir{newDir}
和config setdbfilename{newFileName}
運行期動態執行,當下次運行時RDB
文件會保存到新目錄。config set dir{newDir}
在線修改文件路徑到可用的磁盤路徑,以後執行bgsave
進行磁盤切換,一樣適用於AOF
持久化文件。RDB
文件作壓縮處理,壓縮後的文件遠遠小於內存大小,默認開啓,能夠經過參數config set rdbcompression{yes|no}
動態修改。RDB
會消耗CPU
,可是能大幅下降文件的大小,方便保存到硬盤或經過網絡發送給從節點,所以線上建議開啓。RDB
文件是單一緊湊的二進制文件,比較適合作冷備,全量複製的場景。能夠將一個時間內產生的RDB
文件複製到本地或者存儲到雲端,這樣能夠產生多個不一樣時間段內的數據備份,從而達到容災恢復。RDB
對 Redis 對外提供的讀寫服務,影響很是小,可讓 Redis 保持高性能,由於 Redis 主進程只須要fork
一個子進程,讓子進程執行磁盤IO
操做來進行RDB
持久化便可。AOF
(下篇會弄它)持久化機制來講,直接基於 RDB 數據文件來重啓和恢復 Redis 進程,更加快速,由於RDB
存儲的就是數據,而AOF
存儲的是操做命令。RDB
持久化丟失的數據可能會比AOF
多。由於RDB
是按照時間保存的快照,因此若是在這個時間段內沒有執行RDB
操做,那這段時間的數據就丟失了。RDB
持久化一般都要fork
一個子進程來執行。當數據量較大時,fork
的過程是比較耗時的。RDB
沒法實現實時或者秒級持久化。本期就到這啦,有不對的地方歡迎好哥哥們評論區留言,另外求關注、求點贊