10 分鐘徹底理解 Redis 的持久化和主從複製
在這篇文章,我們學習有關 Redis 方面知識的,一起了解一下其中一個非常重要的內容:Redis 的持久化機制。
什麼是 Redis 持久化?
Redis 作爲一個鍵值對內存數據庫 (NoSQL),數據都存儲在內存當中,在處理客戶端請求時,所有操作都在內存當中進行,如下所示:
這樣做有什麼問題呢?
其實,只要稍微有點計算機基礎知識的人都知道,存儲在內存當中的數據,只要服務器關機 (各種原因引起的),內存中的數據就會消失了,不僅服務器關機會造成數據消失,Redis 服務器守護進程退出,內存中的數據也一樣會消失。
對於只把 Redis 當緩存來用的項目來說,數據消失或許問題不大,重新從數據源把數據加載進來就可以了,但如果直接把用戶提交的業務數據存儲在 Redis 當中,把 Redis 作爲數據庫來使用,在其放存儲重要業務數據,那麼 Redis 的內存數據丟失所造成的影響也許是毀滅性。
爲了避免內存中數據丟失,Redis 提供了對持久化的支持,我們可以選擇不同的方式將數據從內存中保存到硬盤當中,使數據可以持久化保存。
Redis 提供了 RDB 和 AOF 兩種不同的數據持久化方式,下面我們就來詳細介紹一下這種不同的持久化方式吧。
RDB
RDB 是一種快照存儲持久化方式,具體就是將 Redis 某一時刻的內存數據保存到硬盤的文件當中,默認保存的文件名爲 dump.rdb,而在 Redis 服務器啓動時,會重新加載 dump.rdb 文件的數據到內存當中恢復數據。
開啓 RDB 持久化方式
開啓 RDB 持久化方式很簡單,客戶端可以通過向 Redis 服務器發送 save 或 bgsave 命令讓服務器生成 rdb 文件,或者通過服務器配置文件指定觸發 RDB 條件。
1. save 命令
save 命令是一個同步操作。
# 同步數據到磁盤上
> save
當客戶端向服務器發送 save 命令請求進行持久化時,服務器會阻塞 save 命令之後的其他客戶端的請求,直到數據同步完成。
如果數據量太大,同步數據會執行很久,而這期間 Redis 服務器也無法接收其他請求,所以,最好不要在生產環境使用
save
命令。
2. bgsave
與 save 命令不同,bgsave 命令是一個異步操作。
# 異步保存數據集到磁盤上
> bgsave
當客戶端發服務發出 bgsave 命令時,Redis 服務器主進程會 forks 一個子進程來數據同步問題,在將數據保存到 rdb 文件之後,子進程會退出。
所以,與 save 命令相比,Redis 服務器在處理 bgsave 採用子線程進行 IO 寫入,而主進程仍然可以接收其他請求,但 forks 子進程是同步的,所以 forks 子進程時,一樣不能接收其他請求,這意味着,如果 forks 一個子進程花費的時間太久 (一般是很快的),bgsave 命令仍然有阻塞其他客戶的請求的情況發生。
3. 服務器配置自動觸發
除了通過客戶端發送命令外,還有一種方式,就是在 Redis 配置文件中的 save 指定到達觸發 RDB 持久化的條件,比如【多少秒內至少達到多少寫操作】就開啓 RDB 數據同步。
例如我們可以在配置文件 redis.conf 指定如下的選項:
# 900s內至少達到一條寫命令
save 900 1
# 300s內至少達至10條寫命令
save 300 10
# 60s內至少達到10000條寫命令
save 60 10000
之後在啓動服務器時加載配置文件。
# 啓動服務器加載配置文件
redis-server redis.conf
這種通過服務器配置文件觸發 RDB 的方式,與 bgsave 命令類似,達到觸發條件時,會 forks 一個子進程進行數據同步,不過最好不要通過這方式來觸發 RDB 持久化,因爲設置觸發的時間太短,則容易頻繁寫入 rdb 文件,影響服務器性能,時間設置太長則會造成數據丟失。
rdb 文件
前面介紹了三種讓服務器生成 rdb 文件的方式,無論是由主進程生成還是子進程來生成,其過程如下:
-
生成臨時 rdb 文件,並寫入數據。
-
完成數據寫入,用臨時文代替代正式 rdb 文件。
-
刪除原來的 db 文件。
RDB 默認生成的文件名爲 dump.rdb,當然,我可以通過配置文件進行更加詳細配置,比如在單機下啓動多個 redis 服務器進程時,可以通過端口號配置不同的 rdb 名稱,如下所示:
# 是否壓縮rdb文件
rdbcompression yes
# rdb文件的名稱
dbfilename redis-6379.rdb
# rdb文件保存目錄
dir ~/redis/
RDB 的幾個優點
-
與 AOF 方式相比,通過 rdb 文件恢復數據比較快。
-
rdb 文件非常緊湊,適合於數據備份。
-
通過 RDB 進行數據備,由於使用子進程生成,所以對 Redis 服務器性能影響較小。
RDB 的幾個缺點
-
如果服務器宕機的話,採用 RDB 的方式會造成某個時段內數據的丟失,比如我們設置 10 分鐘同步一次或 5 分鐘達到 1000 次寫入就同步一次,那麼如果還沒達到觸發條件服務器就死機了,那麼這個時間段的數據會丟失。
-
使用 save 命令會造成服務器阻塞,直接數據同步完成才能接收後續請求。
-
使用 bgsave 命令在 forks 子進程時,如果數據量太大,forks 的過程也會發生阻塞,另外,forks 子進程會耗費內存。
AOF
聊完了 RDB,來聊聊 Redis 的另外一個持久化方式:AOF(Append-only file)。
與 RDB 存儲某個時刻的快照不同,AOF 持久化方式會記錄客戶端對服務器的每一次寫操作命令,並將這些寫操作以 Redis 協議追加保存到以後綴爲 aof 文件末尾,在 Redis 服務器重啓時,會加載並運行 aof 文件的命令,以達到恢復數據的目的。
開啓 AOF 持久化方式
Redis 默認不開啓 AOF 持久化方式,我們可以在配置文件中開啓並進行更加詳細的配置,如下面的 redis.conf 文件:
# 開啓aof機制
appendonly yes
# aof文件名
appendfilename "appendonly.aof"
# 寫入策略,always表示每個寫操作都保存到aof文件中,也可以是everysec或no
appendfsync always
# 默認不重寫aof文件
no-appendfsync-on-rewrite no
# 保存目錄
dir ~/redis/
三種寫入策略
在上面的配置文件中,我們可以通過 appendfsync 選項指定寫入策略,有三個選項。
appendfsync always
# appendfsync everysec
# appendfsync no
1. always
客戶端的每一個寫操作都保存到 aof 文件當,這種策略很安全,但是每個寫請注都有 IO 操作,所以也很慢。
2. everysec
appendfsync 的默認寫入策略,每秒寫入一次 aof 文件,因此,最多可能會丟失 1s 的數據。
3. no
Redis 服務器不負責寫入 aof,而是交由操作系統來處理什麼時候寫入 aof 文件。更快,但也是最不安全的選擇,不推薦使用。
AOF 文件重寫
AOF 將客戶端的每一個寫操作都追加到 aof 文件末尾,比如對一個 key 多次執行 incr 命令,這時候,aof 保存每一次命令到 aof 文件中,aof 文件會變得非常大。
incr num 1
incr num 2
incr num 3
incr num 4
incr num 5
incr num 6
...
incr num 100000
aof 文件太大,加載 aof 文件恢復數據時,就會非常慢,爲了解決這個問題,Redis 支持 aof 文件重寫,通過重寫 aof,可以生成一個恢復當前數據的最少命令集,比如上面的例子中那麼多條命令,可以重寫爲:
set num 100000
aof 文件是一個二進制文件,並不是像上面的例子一樣,直接保存每個命令,而使用 Redis 自己的格式,上面只是方便演示。
兩種重寫方式
通過在 redis.conf 配置文件中的選項 no-appendfsync-on-rewrite 可以設置是否開啓重寫,這種方式會在每次 fsync 時都重寫,影響服務器性以,因此默認值爲 no,不推薦使用。
# 默認不重寫aof文件
no-appendfsync-on-rewrite no
客戶端向服務器發送 bgrewriteaof 命令,也可以讓服務器進行 AOF 重寫。
# 讓服務器異步重寫追加aof文件命令
> bgrewriteaof
重寫 aof 文件的好處
-
壓縮 aof 文件,減少磁盤佔用量。
-
將 aof 的命令壓縮爲最小命令集,加快了數據恢復的速度。
AOF 文件損壞
在寫入 aof 日誌文件時,如果 Redis 服務器宕機,則 aof 日誌文件文件會出格式錯誤,在重啓 Redis 服務器時,Redis 服務器會拒絕載入這個 aof 文件,可以通過以下步驟修復 aof 並恢復數據。
-
備份現在 aof 文件,以防萬一。
-
使用 redis-check-aof 命令修復 aof 文件,該命令格式如下:
# 修復aof日誌文件
$ redis-check-aof -fix file.aof
- 重啓 Redis 服務器,加載已經修復的 aof 文件,恢復數據。
AOF 的優點
AOF 只是追加日誌文件,因此對服務器性能影響較小,速度比 RDB 要快,消耗的內存較少。
AOF 的缺點
-
AOF 方式生成的日誌文件太大,即使通過 AFO 重寫,文件體積仍然很大。
-
恢復數據的速度比 RDB 慢。
選擇 RDB 還是 AOF 呢?
通過上面的介紹,我們瞭解了 RDB 與 AOF 各自的優點與缺點,到底要如何選擇呢?
通過下面的表示,我們可以從幾個方面對比一下 RDB 與 AOF, 在應用時,要根本自己的實際需求,選擇 RDB 或者 AOF,其實,如果想要數據足夠安全,可以兩種方式都開啓,但兩種持久化方式同時進行 IO 操作,會嚴重影響服務器性能,因此有時候不得不做出選擇。
當 RDB 與 AOF 兩種方式都開啓時,Redis 會優先使用 AOF 日誌來恢復數據,因爲 AOF 保存的文件比 RDB 文件更完整。
小結
上面講了一大堆 Redis 的持久化機制的知識,其實,如果你只是單純把 Redis 作爲緩存服務器,那麼可以完全不用考慮持久化,但是,在如今的大多數服務器架構中,Redis 的單單只是扮演一個緩存服務器的角色,還可以作爲數據庫,保存我們的業務數據,此時,我們則需要好好了解有關 Redis 持久化策略的區別與選擇。
作者:張君鴻
https://juejin.im/post/5d09a9ff51882577eb133aa9
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/isA3B8mXspmqdki0z2FJlg