對于快照來說,所謂“連拍”就是指連續(xù)地做快照。這樣一來,快照的間隔時間變得很短,即使某一時刻發(fā)生宕機了,因為上一時刻快照剛執(zhí)行,丟失的數(shù)據(jù)也不會太多。但是,這其中的快照間隔時間就很關(guān)鍵了。
如下圖所示,我們先在 T0 時刻做了一次快照,然后又在 T0+t 時刻做了一次快照,在這期間,數(shù)據(jù)塊 5 和 9 被修改了。如果在 t 這段時間內(nèi),機器宕機了,那么,只能按照 T0 時刻的快照進行恢復(fù)。此時,數(shù)據(jù)塊 5 和 9 的修改值因為沒有快照記錄,就無法恢復(fù)了。
所以,要想盡可能恢復(fù)數(shù)據(jù),t 值就要盡可能小,t 越小,就越像“連拍”。那么,t 值可以小到什么程度呢,比如說是不是可以每秒做一次快照?畢竟,每次快照都是由 bgsave 子進程在后臺執(zhí)行,也不會阻塞主線程。
這種想法其實是錯誤的。雖然 bgsave 執(zhí)行時不阻塞主線程,但是,如果頻繁地執(zhí)行全量快照,也會帶來兩方面的開銷:
一方面,頻繁將全量數(shù)據(jù)寫入磁盤,會給磁盤帶來很大壓力,多個快照競爭有限的磁盤帶寬,前一個快照還沒有做完,后一個又開始做了,容易造成惡性循環(huán)。
另一方面,bgsave 子進程需要通過 fork 操作從主線程創(chuàng)建出來。雖然,子進程在創(chuàng)建后不會再阻塞主線程,但是,fork 這個創(chuàng)建過程本身會阻塞主線程,而且主線程的內(nèi)存越大,阻塞時間越長。如果頻繁 fork 出 bgsave 子進程,這就會頻繁阻塞主線程了。
那么,有什么其他好方法嗎?此時,我們可以做增量快照,就是指做了一次全量快照后,后續(xù)的快照只對修改的數(shù)據(jù)進行快照記錄,這樣可以避免每次全量快照的開銷。這個比較好理解。
但是它需要我們使用額外的元數(shù)據(jù)信息去記錄哪些數(shù)據(jù)被修改了,這會帶來額外的空間開銷問題。那么,還有什么方法既能利用 RDB 的快速恢復(fù),又能以較小的開銷做到盡量少丟數(shù)據(jù)呢?RDB和AOF的混合方式。