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

談?wù)凴edis的持久化—AOF日志與RDB快照

數(shù)據(jù)庫 其他數(shù)據(jù)庫 Redis
對于Mysql,數(shù)據(jù)是持久化在磁盤上的。如果誤刪數(shù)據(jù),可以使用binlog進行恢復(fù);突然宕機時,其本身可以借助redo log進行崩潰恢復(fù)。

[[429431]]

一、前言

對于Mysql,數(shù)據(jù)是持久化在磁盤上的。如果誤刪數(shù)據(jù),可以使用binlog進行恢復(fù);突然宕機時,其本身可以借助redo log進行崩潰恢復(fù)。

更多關(guān)于Mysql日志的內(nèi)容,可以參考我的另外一篇文章數(shù)據(jù)庫日志——binlog、redo log、undo log掃盲

而對于Redis,一般是把數(shù)據(jù)直接存儲在內(nèi)存中。如果不做任何持久化工作,在出現(xiàn)宕機后,內(nèi)存中的全部數(shù)據(jù)就會丟失。

顯然,業(yè)務(wù)方是不能容忍這樣的情況發(fā)生的。好在Redis提供了一系列的持久化機制,分別是AOF日志與RDB快照。

二、AOF

AOF全稱是Append Only File,Redis每次執(zhí)行完一個寫類型的語句后,會將該語句以某種格式使用追加的方式順序?qū)懭階OF日志中。

值得注意的是,AOF是默認不開啟的。

 

[[429432]]

AOF日志的格式

以winows為例,進入到redis安裝目錄中的redis.windows.conf中,將appendonly的值修改為yes,即可開啟AOF

 

  1. # 默認關(guān)閉 
  2. appendonly yes 
  3.  
  4. # AOF的默認文件名稱 
  5. appendfilename "appendonly.aof" 

 

當執(zhí)行以下命令后

 

  1. set java helloworld 

在appendonly.aof文件中,可以看到以下內(nèi)容

 

  1. *3            代表當前命令有3個部分 
  2. $3            第1部分命令的長度,3個字符 
  3. set           第1部分命令 
  4. $4            第2部分命令的長度,4個字符 
  5. java          第2部分命令 
  6. $10           第3部分命令的長度,10個字符 
  7. helloworld    第3部分命令 

當我們首次使用某個客戶端執(zhí)行命令時,客戶端會自動幫我們補充select 0(即選擇編號0的數(shù)據(jù)庫),這個命令也會被保存在AOF日志中。

寫AOF日志的流程

大致的流程如圖所示

 

 

 

 

在server中,主線程執(zhí)行完命令之后,會立即將命令寫入AOF緩沖中。之后會調(diào)用系統(tǒng)函數(shù)write(),將命令寫入內(nèi)核緩沖區(qū),并返回給客戶端成功的響應(yīng)。

內(nèi)核會在合適的時機將內(nèi)核緩沖區(qū)的中的數(shù)據(jù)寫入到磁盤中。

我們設(shè)想其中某個階段宕機時,會不會產(chǎn)生不一致的情況:

1、如果命令執(zhí)行成功,但寫入AOF緩存前崩潰重啟,客戶端會收到執(zhí)行失敗或超時的響應(yīng)。重啟之后AOF文件中沒有該條數(shù)據(jù),這個時候,數(shù)據(jù)是一致的。

2、如果命令執(zhí)行成功,寫入AOF緩存成功,但調(diào)用write時崩潰重啟。其實這種情況和第一條一樣,恢復(fù)后數(shù)據(jù)還是一致的。

3、如果命令執(zhí)行、寫入AOF緩存與內(nèi)核緩存都成功,客戶端會收到成功的響應(yīng)。如果這個時候機器宕機,內(nèi)核緩沖區(qū)中的數(shù)據(jù)將會丟失,也就是最后的AOF文件缺少該條命令,恢復(fù)后,就會產(chǎn)生數(shù)據(jù)不一致的情況。

第3種情況發(fā)生時,就會出現(xiàn)數(shù)據(jù)不一致的后果。怎么處理呢,很簡單啊,變異步為同步不就行了嗎。

調(diào)用write寫入內(nèi)核緩沖區(qū)后,再調(diào)用fsync強制讓內(nèi)核緩沖區(qū)中的數(shù)據(jù)刷到磁盤上,刷盤成功后,再返回給客戶端響應(yīng)。

這樣的解決方式看似可以,但是刷盤的操作非常耗時。在Redis執(zhí)行大量命令的時候,會一直進行不斷的刷盤,當磁盤壓力過大時,會阻塞下一個命令的執(zhí)行,大大降低性能。

看來得把握刷盤的時機,刷得慢了,機器崩潰恢復(fù)后就會丟失大量數(shù)據(jù)。刷得快了,就會嚴重降低性能。

不過,Redis本身也提供了3種寫回策略。

寫回策略

  • always 同步寫回。每執(zhí)行一條命令,寫完AOF日志后,再返回。
  • everysec 每秒寫回。執(zhí)行命令后,將數(shù)據(jù)寫入到內(nèi)核緩沖區(qū)就返回。只有會有一個線程,執(zhí)行每秒刷盤的定時任務(wù)。
  • no 由內(nèi)核自行控制的寫回。每執(zhí)行一條命令,將數(shù)據(jù)寫入到內(nèi)核緩沖區(qū)就返回。內(nèi)核會在合適的時機刷盤。

這3種策略體現(xiàn)了不同的刷盤頻率,因此擁有不同級別的一致性與性能。

always策略最大程度上保證數(shù)據(jù)不丟失,但性能最差。

no策略性能最好,但在機器崩潰重啟后會丟失比較多的數(shù)據(jù)。

everysec是一種折中的策略,較always有不錯的性能。在極端的情況下,只會丟失1秒內(nèi)的數(shù)據(jù),是比較推薦的方式。

redis.windows.conf中有appendfsync配置項,用來配置寫回策略,默認的策略是everysec 。

隨著Redis不斷記錄AOF日志,AOF日志文件將變得越來越大,用作恢復(fù)的時間也將越長。因此需要一種方式減少文件的大小,這時候AOF重寫就派上用場了。

AOF重寫

在出現(xiàn)觸發(fā)重寫的條件時(例如AOF文件達到某個閾值),Redis掃描整個庫的所有數(shù)據(jù),將數(shù)據(jù)以命令的方式記錄在新的AOF日志中,待記錄完成后,使用新的AOF日志替換舊的即可。

舊日志中,可能存有對同一個key的多次操作命令,重寫的目的就是取最后一次有效的命令,刪除那些歷史命令,從而達到瘦身、壓縮的效果。

剛才提到,AOF重寫會掃描整個庫的數(shù)據(jù),因此注定就是一個非常耗時的操作,那么就不會在主線程中做,而是通過主線程fork出一個子進程進行重寫的。

重寫的流程圖如下:

 

 

 

 

1、當AOF日志文件的大小超過執(zhí)行的閾值后,就會觸發(fā)AOF重寫

2、主線程fork出一個子進程,fork的過程仍然是阻塞的。fork完之后,主線程依然可以接受命令并處理

3、子進程與主線程共享一個實例的所有數(shù)據(jù),子進程會對整個實例進行掃描,將其中的數(shù)據(jù)以命令的格式寫入到重寫日志中。

4、在子進程重寫的過程中,主線程可以接受命令,假設(shè)這個時候執(zhí)行了一條寫命令。

5、主線程會將數(shù)據(jù)存入到庫中,利用寫時復(fù)制技術(shù),子進程不會感知到數(shù)據(jù)有任何變化。

6、主線程將日志先寫入AOF緩沖區(qū),再寫入重寫緩沖區(qū)。

7、由特定寫回策略,將緩沖區(qū)中的數(shù)據(jù)寫入到舊的AOF日志中。

8、當子進程結(jié)束掃描,并且將所有命令寫入重寫日志后,再將重寫緩沖區(qū)中的數(shù)據(jù)追加到重寫日志中。

9、最后一步,主線程感知到子進程重寫日志完成,于是使用新的日志文件替換舊的文件。

也許有人會發(fā)出以下的疑問

為什么是fork出子進程,直接使用子線程不是也可以嗎?

如果是創(chuàng)建出來一個子線程,那么主線程在寫入,子線程在讀取,是需要通過加鎖的方式來保證線程安全的,加鎖就意味著降低性能。

而如果是fork出來子進程,主線程和子進程同樣需要共享數(shù)據(jù),當主線程寫入數(shù)據(jù)的時候,會利用寫時復(fù)制技術(shù),避免加鎖。

什么是寫時復(fù)制?

大家應(yīng)該都知道三角函數(shù)吧,嗯,這和寫時復(fù)制沒什么關(guān)系。

 

[[429433]]

 

CopyOnWriteArrayList就利用到了寫時復(fù)制,讀不加鎖,寫則是復(fù)制一份數(shù)組出來,在新的數(shù)組上進行修改,最后替換引用。非常適合應(yīng)用于讀多寫少的場景,缺點是在替換引用前,線程讀到的是舊數(shù)據(jù)。

主線程在fork出一個子進程的時候,會將自己的頁表(虛擬地址與物理地址的映射表)復(fù)制一份出來給子進程,而不是直接復(fù)制內(nèi)存。否則在重寫的時候,Redis占用內(nèi)存會立即翻倍。

這樣的話,子進程就可以隨意訪問主線程中的數(shù)據(jù)。而當主線程修改一些實例數(shù)據(jù)時,就會復(fù)制一份物理內(nèi)存出來,并變動主線程的頁表,在新的內(nèi)存地址上存儲寫之后的數(shù)據(jù)。因為沒有變動子進程的頁表,因此主線程寫入的數(shù)據(jù)對子進程不可見。

重寫AOF緩沖區(qū)的作用是什么?

CopyOnWriteArrayList的缺點在于讀到的可能是舊數(shù)據(jù),子進程在掃描的時候,其實掃描到的也是舊數(shù)據(jù),因此需要在重寫結(jié)束后做補償。

子進程在重寫的過程中,掃描的數(shù)據(jù)是fork動作結(jié)束的那一刻的快照。而在重寫的過程中,主線程依然可以執(zhí)行命令,那么這些多出來的寫命令就可以放在一個獨立的重寫緩沖區(qū)中。在重寫完成后,再將重寫緩沖區(qū)中的內(nèi)容追加到重寫日志中,這就保證了數(shù)據(jù)的一致。

盡管存在AOF重寫機制,但重寫后的日志文件還是大,恢復(fù)速度較慢。

有沒有一種直接存儲數(shù)據(jù),而不是存儲命令(命令的大小顯然大于數(shù)據(jù)本身)的方式呢?RDB就閃亮登場了!

三、RDB

RDB的全稱是Redis Database Backup,即數(shù)據(jù)備份。

會將某一時刻內(nèi)的所有數(shù)據(jù)生成一個快照文件。該文件是一種經(jīng)過壓縮的二進制文件,默認名稱為dump.rdb,可通過修改dbfilename參數(shù)來改變RDB文件名。

快照文件僅保存數(shù)據(jù),不保存額外的操作命令,且經(jīng)過壓縮,因此在恢復(fù)速度上快于AOF。但RDB沒法做到實時的持久化,而AOF可以基本做到。

如何讓Redis生成RDB文件

通過save命令手動觸發(fā)

直接在主線程中執(zhí)行,會阻塞其他命令

通過bgsave命令手動觸發(fā)

主線程fork出來一個子進程,由子進程去執(zhí)行備份。

整個fork的過程,是會阻塞主線程的。由于不會復(fù)制物理內(nèi)存,因此fork是快速的。

fork結(jié)束后,主線程依然可以執(zhí)行其他的命令。

通過配置自動觸發(fā)

redis.windows.conf中有如下的幾個配置可用于觸發(fā)生成RDB文件

 

  1. # 900秒內(nèi)至少出現(xiàn)1條寫命令就觸發(fā) 
  2. save 900 1 
  3.  
  4. # 300秒內(nèi)至少出現(xiàn)10條寫命令就觸發(fā) 
  5. save 300 10 
  6.  
  7. # 60秒內(nèi)至少出現(xiàn)10000條寫命令就觸發(fā) 
  8. save 60 10000 

 

這種方式,也是通過fork出一個子進程來做的。

三種方式的觸發(fā)流程

 

 

 

 

客戶端使用bgsave命令時,主線程fork出來子進程,由子進程完成備份。

在子進程備份期間,主線程依然可以執(zhí)行命令。但該條數(shù)據(jù)并不會被子進程掃描到,和AOF重寫一樣,都利用到了寫時復(fù)制。

既然RDB文件占用小,恢復(fù)速度快,那可以大幅增加RDB生成的頻率嗎?

那顯然是不可以的,有可能上一輪RDB還未生成,下一輪又開始了。而且也存在性能問題,save全程都會阻塞主線程,bgsave的fork操作同樣也會阻塞主線程。

當然,RDB這種方式,如果在持久化的過程中發(fā)生宕機,會丟失在上次備份之后產(chǎn)生的所有數(shù)據(jù)。

四、AOF與RDB的特點總結(jié)

下面使用一張表格來直觀地展示兩者之間的優(yōu)缺點

 

 

另外值得注意的是,當同時開啟AOF與RDB時,Redis會優(yōu)先使用AOF日志來恢復(fù)數(shù)據(jù)。

RDB相比而言,會丟失較多的數(shù)據(jù)。AOF只有在實例數(shù)據(jù)比較大的時候,恢復(fù)速度才慢。

五、Redis4.0混合持久化模式

既然AOF與RDB獨有各自的優(yōu)勢,能否結(jié)合二者的特點呢?

在Redis4.0中,出現(xiàn)了一個新的模式——混合持久化。具體來講,就是全量RDB+增量AOF,將兩種類型的日志文件存放在一起。

RDB可以以較低的頻率執(zhí)行,兩次RDB之間的產(chǎn)生的增量數(shù)據(jù)記錄在AOF日志中,因此增量AOF日志的文件很小。

 

因此Redis在恢復(fù)時,先加載RDB數(shù)據(jù),再重放增量的AOF日志。不需要像之前重放全量AOF日志,因此恢復(fù)效率大大提升。

 

責任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2023-03-13 08:08:48

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

2021-07-18 07:59:42

RedisRDBAOF

2023-05-11 09:12:35

RedisRDB日志

2024-09-12 08:49:53

2024-03-26 00:03:08

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

2024-09-06 17:49:46

2019-05-17 08:55:49

RedisRDBAOF

2024-09-29 09:25:53

2021-03-10 00:02:01

Redis

2020-01-06 14:54:31

RDBAOFRedis

2025-01-16 14:03:35

Redis

2024-11-22 08:31:32

Redis數(shù)據(jù)持久化高可用

2024-12-20 12:15:06

RedisRDB持久化

2021-02-04 08:01:35

RedisRDBAOF

2020-12-11 11:40:37

RDBAOFRedis

2021-01-05 10:48:38

RedisAOF日志RDB快照

2025-03-14 08:00:00

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

2023-10-12 13:01:29

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

2012-03-07 09:18:06

Redis

2023-10-23 11:22:06

Redis數(shù)據(jù)持久化
點贊
收藏

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