iT邦幫忙

2022 iThome 鐵人賽

DAY 24
0
Software Development

軟體架構師的自我修養系列 第 24

[Day 24] Redis的資料持久化

  • 分享至 

  • xImage
  •  

之前在談到無論是消息佇列或分散式交易時,我們都有提到Redis的持久化不可靠,但我們只是簡短的敘述,並沒有解釋有多麽不可靠。

因此,這篇文章我們將從Redis的實作來告訴你,Redis的持久化到底怎麼運作的。

但在開始前,我們先上結論。

Redis無法保證資料不會遺失,即便使用最嚴格的設定也一樣。

但為了避免大家誤會,這篇文章指的Redis都是指單一一台Redis或者Redis的主從複製,並不包含Redis叢集。

最嚴格的設定則是指開啟Redis的AOF功能,並且在每次指令結束都做fsync。也許有些人對AOF感到陌生,因此我先進一步解釋AOF的原理。

Redis AOF

AOF (Append Only File)是一個類似LSM樹的機制。

當Redis處理指令結束後,Redis會將這個指令以某種形式給存進log檔,而且不會做任何修改,就是直接寫在檔案末尾。

但這個檔案並沒有實際寫進硬碟,而是保留在記憶體中,因此若是Redis直接掛掉,這個AOF依然會遺失。

在泛Unix系統上,要將檔案寫進硬碟使用的是fsync這個系統指令,至於寫進硬碟的時機,在Redis則有三個可以設定的選項。

  1. 完全不使用fsync
  2. 每秒fsync一次
  3. 每次結束指令都做fsync

效能最好的選項是第一個,接著會越來越糟,從這個實驗我們可以看到,第三個選項的效能遠輸LSM樹。

根據官方文件描述,當AOF開啟後且使用第三個選項,資料能夠被妥善保存。但,大錯特錯。

問題在於AOF的發動時機,如果更仔細看Redis的實作,不難發現AOF的發動時機是在處理完指令「之後」。這做法不像是大部分資料庫的WAL (Write Ahead Log)實作,WAL的做法是當在處理指令時同時也在寫入log。

因此,在Redis執行完指令卻馬上掛掉,那麼還來不及執行的AOF也不會生效,修改就遺失了。

每秒fsync一次

每次結束指令都做fsync會嚴重影響效能,因此通常情況,我們僅會採用每秒fsync一次,這同時也是Redis開啟AOF後的預設選項。

那麼,問題來了。

我們真的只會遺失1秒內資料嗎?

答案是,錯。

AOF寫檔案時有兩個步驟:

  • WRITE:把資料寫進檔案
  • SAVE:fsync,也就是實際把檔案寫進硬碟

根據Redis的實作,我把流程圖畫出來如下:

  • 情境1:直接回傳而沒有WRITE和SAVE
  • 情境2:WRITE但沒有SAVE
  • 情境3:既WRITE也SAVE

總結一下,如果Redis掛掉,那麼我們會損失「2秒」內的資料。

另一方面,官網描述的是:

appendfsync everysec: fsync every second. Fast enough (in 2.4 likely to be as fast as snapshotting), and you can lose 1 second of data if there is a disaster.

這是不正確的。

結論

使用Redis的AOF的確可以提升資料持久化的可靠度,但是不可能做到完全沒有資料遺失。

若是希望盡可能地保存資料,那麼就必須要將AOF開啟並開啟RDB(資料快照)。

當然,若是能力允許,應該要使用Redis叢集,這才是最可靠的方式。但一個完整的叢集會需要管理非常多Redis實體,包含三個完整的主本、副本群組和哨兵群組,無論是管理或成本都比單一一個Redis大上不少。


上一篇
[Day 23] MongoDB索引的奧秘
下一篇
[Day 25] 用Redis當鎖?你確定?
系列文
軟體架構師的自我修養31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言