自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Redis宕機(jī)了,Redis如何避免數(shù)據(jù)丟失?

數(shù)據(jù)庫 Redis
對于Redis來說,實現(xiàn)數(shù)據(jù)持久化以避免從后端數(shù)據(jù)庫進(jìn)行恢復(fù)是至關(guān)重要的。目前,Redis實現(xiàn)數(shù)據(jù)持久化主要依靠兩種機(jī)制,即AOF(Append-Only File)日志和RDB快照。

當(dāng)被問到在哪些業(yè)務(wù)場景下你會使用Redis時,你很可能會回答:“我會將其用作緩存,因為Redis將后端數(shù)據(jù)庫中的數(shù)據(jù)存儲在內(nèi)存中,然后直接從內(nèi)存中讀取數(shù)據(jù),因此響應(yīng)速度非???。”沒錯,這確實是Redis的一種常見使用場景,但也存在一個絕對不能忽視的問題:一旦服務(wù)器宕機(jī),內(nèi)存中的數(shù)據(jù)將全部丟失。

解決這個問題的一個顯而易見的方法是從后端數(shù)據(jù)庫中恢復(fù)這些數(shù)據(jù)。然而,這種方法存在兩個問題:首先,頻繁訪問數(shù)據(jù)庫會給數(shù)據(jù)庫帶來巨大的壓力;其次,這些數(shù)據(jù)是從較慢的數(shù)據(jù)庫中讀取出來的,性能肯定不如從Redis中讀取,這會導(dǎo)致使用這些數(shù)據(jù)的應(yīng)用程序響應(yīng)速度變慢。因此,對于Redis來說,實現(xiàn)數(shù)據(jù)持久化以避免從后端數(shù)據(jù)庫進(jìn)行恢復(fù)是至關(guān)重要的。

目前,Redis實現(xiàn)數(shù)據(jù)持久化主要依靠兩種機(jī)制,即AOF(Append-Only File)日志和RDB快照。在接下來的兩個部分,我們將分別深入探討這兩種機(jī)制。首先,讓我們重點關(guān)注AOF日志。

AOF 日志是如何實現(xiàn)的?

說到日志,我們比較熟悉的是數(shù)據(jù)庫的寫前日志(Write Ahead Log, WAL),也就是說,在實際寫數(shù)據(jù)前,先把修改的數(shù)據(jù)記到日志文件中,以便故障時進(jìn)行恢復(fù)。不過,AOF 日志正好相反,它是寫后日志,“寫后”的意思是 Redis 是先執(zhí)行命令,把數(shù)據(jù)寫入內(nèi)存,然后才記錄日志,如下圖所示:

Redis AOF操作過程

那 AOF 為什么要先執(zhí)行命令再記日志呢?要回答這個問題,我們要先知道 AOF 里記錄了什么內(nèi)容。

傳統(tǒng)數(shù)據(jù)庫的日志,例如 redo log(重做日志),記錄的是修改后的數(shù)據(jù),而 AOF 里記錄的是 Redis 收到的每一條命令,這些命令是以文本形式保存的。

我們以 Redis 收到“set testkey testvalue”命令后記錄的日志為例,看看 AOF 日志的內(nèi)容。其中,“*3”表示當(dāng)前命令有三個部分,每部分都是由“$+數(shù)字”開頭,后面緊跟著具體的命令、鍵或值。這里,“數(shù)字”表示這部分中的命令、鍵或值一共有多少字節(jié)。例如,“$3 set”表示這部分有 3 個字節(jié),也就是“set”命令。

Redis AOF日志內(nèi)容

但是,為了避免額外的檢查開銷,Redis 在向 AOF 里面記錄日志的時候,并不會先去對這些命令進(jìn)行語法檢查。所以,如果先記日志再執(zhí)行命令的話,日志中就有可能記錄了錯誤的命令,Redis 在使用日志恢復(fù)數(shù)據(jù)時,就可能會出錯。

而寫后日志這種方式,就是先讓系統(tǒng)執(zhí)行命令,只有命令能執(zhí)行成功,才會被記錄到日志中,否則,系統(tǒng)就會直接向客戶端報錯。所以,Redis 使用寫后日志這一方式的一大好處是,可以避免出現(xiàn)記錄錯誤命令的情況。

除此之外,AOF 還有一個好處:它是在命令執(zhí)行后才記錄日志,所以不會阻塞當(dāng)前的寫操作。

不過,AOF 也有兩個潛在的風(fēng)險。

首先,考慮一種情況:如果剛剛執(zhí)行完一個命令,還來不及將該命令記錄到日志中,Redis服務(wù)器突然宕機(jī),那么這個命令以及相關(guān)數(shù)據(jù)可能會丟失。當(dāng)Redis被用作緩存時,數(shù)據(jù)可以從后端數(shù)據(jù)庫重新加載以進(jìn)行恢復(fù)。但是,如果Redis被直接用作數(shù)據(jù)庫,由于命令尚未被記錄到日志中,因此無法使用日志進(jìn)行數(shù)據(jù)恢復(fù)。

其次,盡管AOF機(jī)制避免了當(dāng)前命令的寫入日志時的阻塞,但這可能會帶來潛在的阻塞風(fēng)險。這是因為AOF日志寫入也是在Redis的主線程中進(jìn)行的。如果在將日志寫入磁盤時,磁盤寫入壓力很大,這將導(dǎo)致寫入操作非常緩慢,從而影響后續(xù)操作的執(zhí)行。

經(jīng)過仔細(xì)分析,你會發(fā)現(xiàn)這兩種風(fēng)險都與AOF寫回磁盤的時機(jī)有關(guān)。這也就表明,如果我們能夠精確控制命令執(zhí)行后AOF日志寫回磁盤的時機(jī),那么這兩種風(fēng)險就能夠得到有效地解決。

三種寫回策略

關(guān)于AOF機(jī)制的問題,有三種不同的策略,對應(yīng)于AOF配置項appendfsync的三個可選值。

  • Always,同步寫回:在每個寫命令執(zhí)行完后,它會立即將日志同步寫回到磁盤。
  • Everysec,每秒寫回:在每個寫命令執(zhí)行完后,它僅將日志寫入AOF文件的內(nèi)存緩沖區(qū),然后每隔一秒才將緩沖區(qū)中的內(nèi)容寫入磁盤。
  • No,操作系統(tǒng)控制的寫回:在每個寫命令執(zhí)行完后,它也只是將日志寫入AOF文件的內(nèi)存緩沖區(qū),而將寫回磁盤的時機(jī)由操作系統(tǒng)控制。

然而,針對避免主線程阻塞和減少數(shù)據(jù)丟失問題,這三種寫回策略都無法做到完美的平衡。以下是對它們的分析:

  • 同步寫回可以基本保證數(shù)據(jù)不會丟失,但它在每個寫命令之后都需要執(zhí)行一個相對較慢的落盤操作,這不可避免地會影響主線程的性能。
  • 盡管操作系統(tǒng)控制的寫回在寫完緩沖區(qū)后可以繼續(xù)執(zhí)行后續(xù)命令,但它失去了對落盤時機(jī)的控制,只要AOF記錄未寫回磁盤,一旦發(fā)生宕機(jī),對應(yīng)的數(shù)據(jù)就會丟失。
  • 每秒寫回采用了一秒寫回一次的頻率,避免了與“同步寫回”相關(guān)的性能開銷,但如果發(fā)生宕機(jī),上一秒內(nèi)未寫回磁盤的命令操作仍然會丟失。因此,這個策略可以視為在避免影響主線程性能和避免數(shù)據(jù)丟失之間的一種妥協(xié)。

我把這三種策略的寫回時機(jī),以及優(yōu)缺點匯總在了一張表格里,以方便你隨時查看。

在這個階段,我們可以根據(jù)系統(tǒng)對高性能和高可靠性的需求來選擇適合的寫回策略??偨Y(jié)來說:

  • 如果追求高性能,可以選擇No策略。
  • 如果需要高可靠性保證,應(yīng)選擇Always策略。
  • 如果能夠容忍一定程度的數(shù)據(jù)丟失,同時希望性能受到較小影響,那么Everysec策略是一個不錯的選擇。

然而,僅僅根據(jù)系統(tǒng)性能需求選擇寫回策略并不能完全保障系統(tǒng)的順利運行。這是因為AOF以文件形式記錄接收到的所有寫命令。隨著寫命令的不斷增加,AOF文件會變得越來越大。這會引發(fā)性能問題,主要體現(xiàn)在以下三個方面:

  • 文件系統(tǒng)本身對文件大小有限制,無法容納過大的文件。
  • 如果AOF文件過大,繼續(xù)往其中追加命令記錄將導(dǎo)致效率下降。
  • 在發(fā)生宕機(jī)時,AOF文件中記錄的每個命令都必須逐個重新執(zhí)行以進(jìn)行故障恢復(fù)。如果AOF文件過大,恢復(fù)過程將變得極其緩慢,從而影響Redis的正常運行。

因此,我們必須采取控制措施來解決AOF文件過大的問題,而AOF重寫機(jī)制就是其中一種解決方案。

日志文件太大了怎么辦?

AOF重寫機(jī)制的核心原理很簡單,它的任務(wù)是根據(jù)數(shù)據(jù)庫的當(dāng)前狀態(tài),創(chuàng)建一個全新的AOF文件。這意味著它需要讀取數(shù)據(jù)庫中的所有鍵值對,然后為每個鍵值對生成一條相應(yīng)的寫入命令。例如,當(dāng)它讀取鍵值對"testkey": "testvalue"時,重寫機(jī)制會記錄一條"set testkey testvalue"的命令。這樣,當(dāng)需要進(jìn)行故障恢復(fù)時,可以重新執(zhí)行這些命令,以還原"testkey": "testvalue"的寫入操作。

那么,AOF重寫機(jī)制如何幫助減小日志文件的大小呢?實際上,它具有“多對一”的功能。這意味著,舊日志文件中的多個命令在重寫后的新日志中變成了一條命令。

我們知道,AOF文件以追加的方式記錄接收到的寫命令。當(dāng)一個鍵值對經(jīng)歷多次修改時,AOF文件會記錄多條相應(yīng)的寫命令。然而,在重寫過程中,根據(jù)鍵值對的當(dāng)前狀態(tài),只生成一條對應(yīng)的寫入命令。這意味著,一個鍵值對在重寫后的日志中只需要一條命令,而在日志恢復(fù)時,只需執(zhí)行這一條命令,即可完全還原該鍵值對的寫入操作。這種方式顯著減小了AOF文件的體積,提高了性能。

下面這張圖就是一個例子:

AOF重寫減少日志大小

當(dāng)我們對一個列表先后做了 6 次修改操作后,列表的最后狀態(tài)是[“D”, “C”, “N”],此時,只用 LPUSH u:list “N”, “C”, "D"這一條命令就能實現(xiàn)該數(shù)據(jù)的恢復(fù),這就節(jié)省了五條命令的空間。對于被修改過成百上千次的鍵值對來說,重寫能節(jié)省的空間當(dāng)然就更大了。

不過,雖然 AOF 重寫后,日志文件會縮小,但是,要把整個數(shù)據(jù)庫的最新數(shù)據(jù)的操作日志都寫回磁盤,仍然是一個非常耗時的過程。這時,我們就要繼續(xù)關(guān)注另一個問題了:重寫會不會阻塞主線程?

AOF 重寫會阻塞嗎?

和 AOF 日志由主線程寫回不同,重寫過程是由后臺線程 bgrewriteaof 來完成的,這也是為了避免阻塞主線程,導(dǎo)致數(shù)據(jù)庫性能下降。

我把重寫的過程總結(jié)為“一個拷貝,兩處日志”。

“一個拷貝”就是指,每次執(zhí)行重寫時,主線程 fork 出后臺的 bgrewriteaof 子進(jìn)程。此時,fork 會把主線程的內(nèi)存拷貝一份給 bgrewriteaof 子進(jìn)程,這里面就包含了數(shù)據(jù)庫的最新數(shù)據(jù)。然后,bgrewriteaof 子進(jìn)程就可以在不影響主線程的情況下,逐一把拷貝的數(shù)據(jù)寫成操作,記入重寫日志。

“兩處日志”又是什么呢?

因為主線程未阻塞,仍然可以處理新來的操作。此時,如果有寫操作,第一處日志就是指正在使用的 AOF 日志,Redis 會把這個操作寫到它的緩沖區(qū)。這樣一來,即使宕機(jī)了,這個 AOF 日志的操作仍然是齊全的,可以用于恢復(fù)。

而第二處日志,就是指新的 AOF 重寫日志。這個操作也會被寫到重寫日志的緩沖區(qū)。這樣,重寫日志也不會丟失最新的操作。等到拷貝數(shù)據(jù)的所有操作記錄重寫完成后,重寫日志記錄的這些最新操作也會寫入新的 AOF 文件,以保證數(shù)據(jù)庫最新狀態(tài)的記錄。此時,我們就可以用新的 AOF 文件替代舊文件了。

AOF非阻塞的重寫過程

總結(jié)來說,每次 AOF 重寫時,Redis 會先執(zhí)行一個內(nèi)存拷貝,用于重寫;然后,使用兩個日志保證在重寫過程中,新寫入的數(shù)據(jù)不會丟失。而且,因為 Redis 采用額外的線程進(jìn)行數(shù)據(jù)重寫,所以,這個過程并不會阻塞主線程。

小結(jié)

這篇文章詳細(xì)介紹了Redis中用于防止數(shù)據(jù)丟失的AOF(Append-Only File)方法。這種方法通過逐一記錄執(zhí)行操作命令的方式,以確保在需要數(shù)據(jù)恢復(fù)時能夠逐一執(zhí)行這些命令,從而保證了數(shù)據(jù)的可靠性。

雖然這一方法看似相對簡單,但它充分考慮了對Redis性能的潛在影響。總結(jié)來看,AOF日志提供了三種不同的寫回策略,分別為Always、Everysec和No。這三種策略在可靠性方面從高到低排序,但在性能方面則正好相反,從低到高。

此外,為了避免AOF日志文件變得過大,Redis還引入了AOF重寫機(jī)制。該機(jī)制通過后臺線程根據(jù)數(shù)據(jù)庫內(nèi)數(shù)據(jù)的最新狀態(tài)生成相應(yīng)的插入命令,作為新的AOF日志。這個過程的設(shè)計避免了對主線程的阻塞,從而提高了系統(tǒng)的整體性能。

這三種寫回策略突顯了系統(tǒng)設(shè)計中的重要原則,即權(quán)衡。這意味著需要在性能和可靠性之間找到平衡。我相信這一原則對于系統(tǒng)設(shè)計和開發(fā)來說至關(guān)重要,希望你能深刻理解它,并在實際開發(fā)中應(yīng)用得當(dāng)。

然而,需要注意的是,數(shù)據(jù)持久化和AOF重寫機(jī)制主要在"記錄日志"過程中發(fā)揮作用。例如,選擇合適的數(shù)據(jù)持久化時機(jī)可以避免在記錄日志時阻塞主線程,而AOF重寫機(jī)制則可以防止AOF日志文件無限增長。但在"使用日志"的過程中,即使用AOF進(jìn)行故障恢復(fù)時,所有操作記錄仍然需要逐一執(zhí)行。考慮到Redis的單線程設(shè)計,這個"重放"過程可能會比較慢。

然而,是否有一種方法既能確保數(shù)據(jù)不丟失,又能更快地進(jìn)行數(shù)據(jù)恢復(fù)呢?當(dāng)然,這就是RDB快照的用武之地。在下一篇文章中,我們將深入研究RDB快照的工作原理和應(yīng)用。

責(zé)任編輯:趙寧寧 來源: 碼農(nóng)本農(nóng)
相關(guān)推薦

2021-01-05 10:48:38

RedisAOF日志RDB快照

2021-11-30 06:32:19

Redis宕機(jī)集群

2019-05-15 09:04:47

Redis數(shù)據(jù)存儲數(shù)據(jù)

2024-11-11 07:05:00

Redis哨兵模式主從復(fù)制

2019-05-15 09:44:33

數(shù)據(jù)Redis持久化

2024-02-26 08:10:00

Redis數(shù)據(jù)數(shù)據(jù)庫

2023-10-22 11:17:50

AOFRedis數(shù)據(jù)庫

2020-12-31 07:34:04

Redis數(shù)據(jù)宕機(jī)

2023-11-27 13:18:00

Redis數(shù)據(jù)不丟失

2010-09-09 17:43:03

APC

2024-02-23 14:53:10

Redis持久化

2019-03-13 09:27:57

宕機(jī)Kafka數(shù)據(jù)

2021-05-27 05:29:29

緩存數(shù)據(jù)Redis

2021-01-12 08:03:19

Redis數(shù)據(jù)系統(tǒng)

2022-07-11 08:01:55

Kafka服務(wù)器宕機(jī)

2011-07-27 09:32:27

2023-10-20 13:18:05

Flink數(shù)據(jù)

2025-03-14 12:30:00

Redis RDBRedis數(shù)據(jù)庫

2021-06-04 12:05:03

Redis Bitmap 數(shù)據(jù)庫

2020-03-06 15:36:01

Redis內(nèi)存宕機(jī)
點贊
收藏

51CTO技術(shù)棧公眾號