国产gaysexchina男同gay,japanrcep老熟妇乱子伦视频,吃奶呻吟打开双腿做受动态图,成人色网站,国产av一区二区三区最新精品

AOF

2018-08-02 11:56 更新

AOF

Redis 分別提供了 RDB 和 AOF 兩種持久化機制:

  • RDB 將數(shù)據(jù)庫的快照(snapshot)以二進制的方式保存到磁盤中。
  • AOF 則以協(xié)議文本的方式,將所有對數(shù)據(jù)庫進行過寫入的命令(及其參數(shù))記錄到 AOF 文件,以此達到記錄數(shù)據(jù)庫狀態(tài)的目的。

digraph persistent {    rankdir = LR;    node [shape = circle, style = filled];    edge [style = server [label = "命令請求"]; server -> aof [ label = "網(wǎng)絡協(xié)議格式的\n命令內容"];}" />

本章首先介紹 AOF 功能的運作機制,了解命令是如何被保存到 AOF 文件里的,觀察不同的 AOF 保存模式對數(shù)據(jù)的安全性、以及 Redis 性能的影響。

之后會介紹從 AOF 文件中恢復數(shù)據(jù)庫狀態(tài)的方法,以及該方法背后的實現(xiàn)機制。

最后還會介紹對 AOF 進行重寫以調整文件體積的方法,并研究這種方法是如何在不改變數(shù)據(jù)庫狀態(tài)的前提下進行的。

因為本章涉及 AOF 運行的相關機制,如果還沒了解過 AOF 功能的話,請先閱讀 Redis 持久化手冊中關于 AOF 的部分 。

AOF 命令同步

Redis 將所有對數(shù)據(jù)庫進行過寫入的命令(及其參數(shù))記錄到 AOF 文件,以此達到記錄數(shù)據(jù)庫狀態(tài)的目的,為了方便起見,我們稱呼這種記錄過程為同步。

舉個例子,如果執(zhí)行以下命令:

redis> RPUSH list 1 2 3 4
(integer) 4

redis> LRANGE list 0 -1
1) "1"
2) "2"
3) "3"
4) "4"

redis> KEYS *
1) "list"

redis> RPOP list
"4"

redis> LPOP list
"1"

redis> LPUSH list 1
(integer) 3

redis> LRANGE list 0 -1
1) "1"
2) "2"
3) "3"

那么其中四條對數(shù)據(jù)庫有修改的寫入命令就會被同步到 AOF 文件中:

RPUSH list 1 2 3 4

RPOP list

LPOP list

LPUSH list 1

為了處理的方便,AOF 文件使用網(wǎng)絡通訊協(xié)議的格式來保存這些命令。

比如說,上面列舉的四個命令在 AOF 文件中就實際保存如下:

*2
$6
SELECT
$1
0
*6
$5
RPUSH
$4
list
$1
1
$1
2
$1
3
$1
4
*2
$4
RPOP
$4
list
*2
$4
LPOP
$4
list
*3
$5
LPUSH
$4
list
$1
1

除了 SELECT 命令是 AOF 程序自己加上去的之外,其他命令都是之前我們在終端里執(zhí)行的命令。

同步命令到 AOF 文件的整個過程可以分為三個階段:

  1. 命令傳播:Redis 將執(zhí)行完的命令、命令的參數(shù)、命令的參數(shù)個數(shù)等信息發(fā)送到 AOF 程序中。
  2. 緩存追加:AOF 程序根據(jù)接收到的命令數(shù)據(jù),將命令轉換為網(wǎng)絡通訊協(xié)議的格式,然后將協(xié)議內容追加到服務器的 AOF 緩存中。
  3. 文件寫入和保存:AOF 緩存中的內容被寫入到 AOF 文件末尾,如果設定的 AOF 保存條件被滿足的話, fsync 函數(shù)或者 fdatasync 函數(shù)會被調用,將寫入的內容真正地保存到磁盤中。

以下幾個小節(jié)將詳細地介紹這三個步驟。

命令傳播

當一個 Redis 客戶端需要執(zhí)行命令時,它通過網(wǎng)絡連接,將協(xié)議文本發(fā)送給 Redis 服務器。

比如說,要執(zhí)行命令 SET KEY VALUE ,客戶端將向服務器發(fā)送文本 "*3\r\n$3\r\nSET\r\n$3\r\nKEY\r\n$5\r\nVALUE\r\n"

服務器在接到客戶端的請求之后,它會根據(jù)協(xié)議文本的內容,選擇適當?shù)拿詈瘮?shù),并將各個參數(shù)從字符串文本轉換為 Redis 字符串對象(StringObject)。

比如說,針對上面的 SET 命令例子,Redis 將客戶端的命令指針指向實現(xiàn) SET 命令的 setCommand 函數(shù),并創(chuàng)建三個 Redis 字符串對象,分別保存 SET 、 KEYVALUE 三個參數(shù)(命令也算作參數(shù))。

每當命令函數(shù)成功執(zhí)行之后,命令參數(shù)都會被傳播到 AOF 程序,以及 REPLICATION 程序(本節(jié)不討論這個,列在這里只是為了完整性的考慮)。

這個執(zhí)行并傳播命令的過程可以用以下偽代碼表示:

if (execRedisCommand(cmd, argv, argc) == EXEC_SUCCESS):

    if aof_is_turn_on():
        # 傳播命令到 AOF 程序
        propagate_aof(cmd, argv, argc)

    if replication_is_turn_on():
        # 傳播命令到 REPLICATION 程序
        propagate_replication(cmd, argv, argc)

以下是該過程的流程圖:

digraph propagate {    node [shape = plaintext, style = filled];    edge [style = bold];    // node     exec [label =

aof_choice; aof_choice -> propagate_aof [label = "是"]; propagate_aof -> replication_choice; aof_choice -> replication_choice [label = "否"]; replication_choice -> remaind_jobs [label = "否"]; replication_choice -> propagate_replication [label = "是"]; propagate_replication -> remaind_jobs;}" />

緩存追加

當命令被傳播到 AOF 程序之后,程序會根據(jù)命令以及命令的參數(shù),將命令從字符串對象轉換回原來的協(xié)議文本。

比如說,如果 AOF 程序接受到的三個參數(shù)分別保存著 SET 、 KEYVALUE 三個字符串,那么它將生成協(xié)議文本 "*3\r\n$3\r\nSET\r\n$3\r\nKEY\r\n$5\r\nVALUE\r\n" 。

協(xié)議文本生成之后,它會被追加到 redis.h/redisServer 結構的 aof_buf 末尾。

redisServer 結構維持著 Redis 服務器的狀態(tài),aof_buf 域則保存著所有等待寫入到 AOF 文件的協(xié)議文本:

struct redisServer {

    // 其他域...

    sds aof_buf;

    // 其他域...
};

至此,追加命令到緩存的步驟執(zhí)行完畢。

綜合起來,整個緩存追加過程可以分為以下三步:

  1. 接受命令、命令的參數(shù)、以及參數(shù)的個數(shù)、所使用的數(shù)據(jù)庫等信息。
  2. 將命令還原成 Redis 網(wǎng)絡通訊協(xié)議。
  3. 將協(xié)議文本追加到 aof_buf 末尾。

文件寫入和保存

每當服務器常規(guī)任務函數(shù)被執(zhí)行、或者事件處理器被執(zhí)行時,aof.c/flushAppendOnlyFile 函數(shù)都會被調用,這個函數(shù)執(zhí)行以下兩個工作:

WRITE:根據(jù)條件,將 aof_buf 中的緩存寫入到 AOF 文件。

SAVE:根據(jù)條件,調用 fsyncfdatasync 函數(shù),將 AOF 文件保存到磁盤中。

兩個步驟都需要根據(jù)一定的條件來執(zhí)行,而這些條件由 AOF 所使用的保存模式來決定,以下小節(jié)就來介紹 AOF 所使用的三種保存模式,以及在這些模式下,步驟 WRITE 和 SAVE 的調用條件。

AOF 保存模式

Redis 目前支持三種 AOF 保存模式,它們分別是:

  1. AOF_FSYNC_NO :不保存。
  2. AOF_FSYNC_EVERYSEC :每一秒鐘保存一次。
  3. AOF_FSYNC_ALWAYS :每執(zhí)行一個命令保存一次。

以下三個小節(jié)將分別討論這三種保存模式。

不保存

在這種模式下,每次調用 flushAppendOnlyFile 函數(shù),WRITE 都會被執(zhí)行,但 SAVE 會被略過。

在這種模式下, SAVE 只會在以下任意一種情況中被執(zhí)行:

  • Redis 被關閉
  • AOF 功能被關閉
  • 系統(tǒng)的寫緩存被刷新(可能是緩存已經(jīng)被寫滿,或者定期保存操作被執(zhí)行)

這三種情況下的 SAVE 操作都會引起 Redis 主進程阻塞。

每一秒鐘保存一次

在這種模式中,SAVE 原則上每隔一秒鐘就會執(zhí)行一次,因為 SAVE 操作是由后臺子線程調用的,所以它不會引起服務器主進程阻塞。

注意,在上一句的說明里面使用了詞語“原則上”,在實際運行中,程序在這種模式下對 fsyncfdatasync 的調用并不是每秒一次,它和調用 flushAppendOnlyFile 函數(shù)時 Redis 所處的狀態(tài)有關。

每當 flushAppendOnlyFile 函數(shù)被調用時,可能會出現(xiàn)以下四種情況:

  • 子線程正在執(zhí)行 SAVE ,并且:

  1. 這個 SAVE 的執(zhí)行時間未超過 2 秒,那么程序直接返回,并不執(zhí)行 WRITE 或新的 SAVE 。
  2. 這個 SAVE 已經(jīng)執(zhí)行超過 2 秒,那么程序執(zhí)行 WRITE ,但不執(zhí)行新的 SAVE 。注意,因為這時 WRITE 的寫入必須等待子線程先完成(舊的) SAVE ,因此這里 WRITE 會比平時阻塞更長時間。
  • 子線程沒有在執(zhí)行 SAVE ,并且:

  1. 上次成功執(zhí)行 SAVE 距今不超過 1 秒,那么程序執(zhí)行 WRITE ,但不執(zhí)行 SAVE 。
  2. 上次成功執(zhí)行 SAVE 距今已經(jīng)超過 1 秒,那么程序執(zhí)行 WRITE 和 SAVE 。

可以用流程圖表示這四種情況:

digraph flush {    node [shape = plaintext, style = filled, fillcolor = 

over_2_second_choice [label = "是"]; over_2_second_choice -> not_over_2_second [label = "否"]; over_2_second_choice -> over_2_second [label = "是"]; finish_over_2_second [label = "距離上次 SAVE\n 執(zhí)行成功\n超過 1 秒?", shape = diamond, fillcolor = "#95BBE3"]; no [label = "情況 3 :\n 執(zhí)行 WRITE \n 但不執(zhí)行新的 SAVE "]; yes [label = "情況 4 :\n 執(zhí)行 WRITE 和\n新的 SAVE\n"]; SAVE_running_choice -> finish_over_2_second [label = "否"]; finish_over_2_second -> yes [label = "是"]; finish_over_2_second -> no [label = "否"];}" />

根據(jù)以上說明可以知道,在“每一秒鐘保存一次”模式下,如果在情況 1 中發(fā)生故障停機,那么用戶最多損失小于 2 秒內所產(chǎn)生的所有數(shù)據(jù)。

如果在情況 2 中發(fā)生故障停機,那么用戶損失的數(shù)據(jù)是可以超過 2 秒的。

Redis 官網(wǎng)上所說的,AOF 在“每一秒鐘保存一次”時發(fā)生故障,只丟失 1 秒鐘數(shù)據(jù)的說法,實際上并不準確。

每執(zhí)行一個命令保存一次

在這種模式下,每次執(zhí)行完一個命令之后, WRITE 和 SAVE 都會被執(zhí)行。

另外,因為 SAVE 是由 Redis 主進程執(zhí)行的,所以在 SAVE 執(zhí)行期間,主進程會被阻塞,不能接受命令請求。

AOF 保存模式對性能和安全性的影響

在上一個小節(jié),我們簡短地描述了三種 AOF 保存模式的工作方式,現(xiàn)在,是時候研究一下這三個模式在安全性和性能方面的區(qū)別了。

對于三種 AOF 保存模式,它們對服務器主進程的阻塞情況如下:

  1. 不保存(AOF_FSYNC_NO):寫入和保存都由主進程執(zhí)行,兩個操作都會阻塞主進程。
  2. 每一秒鐘保存一次(AOF_FSYNC_EVERYSEC):寫入操作由主進程執(zhí)行,阻塞主進程。保存操作由子線程執(zhí)行,不直接阻塞主進程,但保存操作完成的快慢會影響寫入操作的阻塞時長。
  3. 每執(zhí)行一個命令保存一次(AOF_FSYNC_ALWAYS):和模式 1 一樣。

因為阻塞操作會讓 Redis 主進程無法持續(xù)處理請求,所以一般說來,阻塞操作執(zhí)行得越少、完成得越快,Redis 的性能就越好。

模式 1 的保存操作只會在AOF 關閉或 Redis 關閉時執(zhí)行,或者由操作系統(tǒng)觸發(fā),在一般情況下,這種模式只需要為寫入阻塞,因此它的寫入性能要比后面兩種模式要高,當然,這種性能的提高是以降低安全性為代價的:在這種模式下,如果運行的中途發(fā)生停機,那么丟失數(shù)據(jù)的數(shù)量由操作系統(tǒng)的緩存沖洗策略決定。

模式 2 在性能方面要優(yōu)于模式 3 ,并且在通常情況下,這種模式最多丟失不多于 2 秒的數(shù)據(jù),所以它的安全性要高于模式 1 ,這是一種兼顧性能和安全性的保存方案。

模式 3 的安全性是最高的,但性能也是最差的,因為服務器必須阻塞直到命令信息被寫入并保存到磁盤之后,才能繼續(xù)處理請求。

綜合起來,三種 AOF 模式的操作特性可以總結如下:

模式 WRITE 是否阻塞? SAVE 是否阻塞? 停機時丟失的數(shù)據(jù)量
AOF_FSYNC_NO 阻塞 阻塞 操作系統(tǒng)最后一次對 AOF 文件觸發(fā) SAVE 操作之后的數(shù)據(jù)。
AOF_FSYNC_EVERYSEC 阻塞 不阻塞 一般情況下不超過 2 秒鐘的數(shù)據(jù)。
AOF_FSYNC_ALWAYS 阻塞 阻塞 最多只丟失一個命令的數(shù)據(jù)。

AOF 文件的讀取和數(shù)據(jù)還原

AOF 文件保存了 Redis 的數(shù)據(jù)庫狀態(tài),而文件里面包含的都是符合 Redis 通訊協(xié)議格式的命令文本。

這也就是說,只要根據(jù) AOF 文件里的協(xié)議,重新執(zhí)行一遍里面指示的所有命令,就可以還原 Redis 的數(shù)據(jù)庫狀態(tài)了。

Redis 讀取 AOF 文件并還原數(shù)據(jù)庫的詳細步驟如下:

  1. 創(chuàng)建一個不帶網(wǎng)絡連接的偽客戶端(fake client)。
  2. 讀取 AOF 所保存的文本,并根據(jù)內容還原出命令、命令的參數(shù)以及命令的個數(shù)。
  3. 根據(jù)命令、命令的參數(shù)和命令的個數(shù),使用偽客戶端執(zhí)行該命令。
  4. 執(zhí)行 2 和 3 ,直到 AOF 文件中的所有命令執(zhí)行完畢。

完成第 4 步之后,AOF 文件所保存的數(shù)據(jù)庫就會被完整地還原出來。

注意,因為 Redis 的命令只能在客戶端的上下文中被執(zhí)行,而 AOF 還原時所使用的命令來自于 AOF 文件,而不是網(wǎng)絡,所以程序使用了一個沒有網(wǎng)絡連接的偽客戶端來執(zhí)行命令。偽客戶端執(zhí)行命令的效果,和帶網(wǎng)絡連接的客戶端執(zhí)行命令的效果,完全一樣。

整個讀取和還原過程可以用以下偽代碼表示:

def READ_AND_LOAD_AOF():

    # 打開并讀取 AOF 文件
    file = open(aof_file_name)
    while file.is_not_reach_eof():

        # 讀入一條協(xié)議文本格式的 Redis 命令
        cmd_in_text = file.read_next_command_in_protocol_format()

        # 根據(jù)文本命令,查找命令函數(shù),并創(chuàng)建參數(shù)和參數(shù)個數(shù)等對象
        cmd, argv, argc = text_to_command(cmd_in_text)

        # 執(zhí)行命令
        execRedisCommand(cmd, argv, argc)

    # 關閉文件
    file.close()

作為例子,以下是一個簡短的 AOF 文件的內容:

*2
$6
SELECT
$1
0
*3
$3
SET
$3
key
$5
value
*8
$5
RPUSH
$4
list
$1
1
$1
2
$1
3
$1
4
$1
5
$1
6

當程序讀入這個 AOF 文件時,它首先執(zhí)行 SELECT 0 命令 ——這個 SELECT 命令是由 AOF 寫入程序自動生成的,它確保程序可以將數(shù)據(jù)還原到正確的數(shù)據(jù)庫上。

然后執(zhí)行后面的 SET key valueRPUSH 1 2 3 4 命令,還原 keylist 兩個鍵的數(shù)據(jù)。

Note

為了避免對數(shù)據(jù)的完整性產(chǎn)生影響,在服務器載入數(shù)據(jù)的過程中,只有和數(shù)據(jù)庫無關的訂閱與發(fā)布功能可以正常使用,其他命令一律返回錯誤。

AOF 重寫

AOF 文件通過同步 Redis 服務器所執(zhí)行的命令,從而實現(xiàn)了數(shù)據(jù)庫狀態(tài)的記錄,但是,這種同步方式會造成一個問題:隨著運行時間的流逝,AOF 文件會變得越來越大。

舉個例子,如果服務器執(zhí)行了以下命令:

RPUSH list 1 2 3 4      // [1, 2, 3, 4]

RPOP list               // [1, 2, 3]

LPOP list               // [2, 3]

LPUSH list 1            // [1, 2, 3]

那么光是記錄 list 鍵的狀態(tài),AOF 文件就需要保存四條命令。

另一方面,有些被頻繁操作的鍵,對它們所調用的命令可能有成百上千、甚至上萬條,如果這樣被頻繁操作的鍵有很多的話,AOF 文件的體積就會急速膨脹,對 Redis 、甚至整個系統(tǒng)的造成影響。

為了解決以上的問題,Redis 需要對 AOF 文件進行重寫(rewrite):創(chuàng)建一個新的 AOF 文件來代替原有的 AOF 文件,新 AOF 文件和原有 AOF 文件保存的數(shù)據(jù)庫狀態(tài)完全一樣,但新 AOF 文件的體積小于等于原有 AOF 文件的體積。

以下就來介紹 AOF 重寫的實現(xiàn)方式。

AOF 重寫的實現(xiàn)

所謂的“重寫”其實是一個有歧義的詞語,實際上,AOF 重寫并不需要對原有的 AOF 文件進行任何寫入和讀取,它針對的是數(shù)據(jù)庫中鍵的當前值。

考慮這樣一個情況,如果服務器對鍵 list 執(zhí)行了以下四條命令:

RPUSH list 1 2 3 4      // [1, 2, 3, 4]

RPOP list               // [1, 2, 3]

LPOP list               // [2, 3]

LPUSH list 1            // [1, 2, 3]

那么當前列表鍵 list 在數(shù)據(jù)庫中的值就為 [1, 2, 3] 。

如果我們要保存這個列表的當前狀態(tài),并且盡量減少所使用的命令數(shù),那么最簡單的方式不是去 AOF 文件上分析前面執(zhí)行的四條命令,而是直接讀取 list 鍵在數(shù)據(jù)庫的當前值,然后用一條 RPUSH 1 2 3 命令來代替前面的四條命令。

再考慮這樣一個例子,如果服務器對集合鍵 animal 執(zhí)行了以下命令:

SADD animal cat                 // {cat}

SADD animal dog panda tiger     // {cat, dog, panda, tiger}

SREM animal cat                 // {dog, panda, tiger}

SADD animal cat lion            // {cat, lion, dog, panda, tiger}

那么使用一條 SADD animal cat lion dog panda tiger 命令,就可以還原 animal 集合的狀態(tài),這比之前的四條命令調用要大大減少。

除了列表和集合之外,字符串、有序集、哈希表等鍵也可以用類似的方法來保存狀態(tài),并且保存這些狀態(tài)所使用的命令數(shù)量,比起之前建立這些鍵的狀態(tài)所使用命令的數(shù)量要大大減少。

根據(jù)鍵的類型,使用適當?shù)膶懭朊顏碇噩F(xiàn)鍵的當前值,這就是 AOF 重寫的實現(xiàn)原理。整個重寫過程可以用偽代碼表示如下:

def AOF_REWRITE(tmp_tile_name):

  f = create(tmp_tile_name)

  # 遍歷所有數(shù)據(jù)庫
  for db in redisServer.db:

    # 如果數(shù)據(jù)庫為空,那么跳過這個數(shù)據(jù)庫
    if db.is_empty(): continue

    # 寫入 SELECT 命令,用于切換數(shù)據(jù)庫
    f.write_command("SELECT " + db.number)

    # 遍歷所有鍵
    for key in db:

      # 如果鍵帶有過期時間,并且已經(jīng)過期,那么跳過這個鍵
      if key.have_expire_time() and key.is_expired(): continue

      if key.type == String:

        # 用 SET key value 命令來保存字符串鍵

        value = get_value_from_string(key)

        f.write_command("SET " + key + value)

      elif key.type == List:

        # 用 RPUSH key item1 item2 ... itemN 命令來保存列表鍵

        item1, item2, ..., itemN = get_item_from_list(key)

        f.write_command("RPUSH " + key + item1 + item2 + ... + itemN)

      elif key.type == Set:

        # 用 SADD key member1 member2 ... memberN 命令來保存集合鍵

        member1, member2, ..., memberN = get_member_from_set(key)

        f.write_command("SADD " + key + member1 + member2 + ... + memberN)

      elif key.type == Hash:

        # 用 HMSET key field1 value1 field2 value2 ... fieldN valueN 命令來保存哈希鍵

        field1, value1, field2, value2, ..., fieldN, valueN =\
        get_field_and_value_from_hash(key)

        f.write_command("HMSET " + key + field1 + value1 + field2 + value2 +\
                        ... + fieldN + valueN)

      elif key.type == SortedSet:

        # 用 ZADD key score1 member1 score2 member2 ... scoreN memberN
        # 命令來保存有序集鍵

        score1, member1, score2, member2, ..., scoreN, memberN = \
        get_score_and_member_from_sorted_set(key)

        f.write_command("ZADD " + key + score1 + member1 + score2 + member2 +\
                        ... + scoreN + memberN)

      else:

        raise_type_error()

      # 如果鍵帶有過期時間,那么用 EXPIREAT key time 命令來保存鍵的過期時間
      if key.have_expire_time():
        f.write_command("EXPIREAT " + key + key.expire_time_in_unix_timestamp())

    # 關閉文件
    f.close()

AOF 后臺重寫

上一節(jié)展示的 AOF 重寫程序可以很好地完成創(chuàng)建一個新 AOF 文件的任務,但是,在執(zhí)行這個程序的時候,調用者線程會被阻塞。

很明顯,作為一種輔佐性的維護手段,Redis 不希望 AOF 重寫造成服務器無法處理請求,所以 Redis 決定將 AOF 重寫程序放到(后臺)子進程里執(zhí)行,這樣處理的最大好處是:

  1. 子進程進行 AOF 重寫期間,主進程可以繼續(xù)處理命令請求。
  2. 子進程帶有主進程的數(shù)據(jù)副本,使用子進程而不是線程,可以在避免鎖的情況下,保證數(shù)據(jù)的安全性。

不過,使用子進程也有一個問題需要解決:因為子進程在進行 AOF 重寫期間,主進程還需要繼續(xù)處理命令,而新的命令可能對現(xiàn)有的數(shù)據(jù)進行修改,這會讓當前數(shù)據(jù)庫的數(shù)據(jù)和重寫后的 AOF 文件中的數(shù)據(jù)不一致。

為了解決這個問題,Redis 增加了一個 AOF 重寫緩存,這個緩存在 fork 出子進程之后開始啟用,Redis 主進程在接到新的寫命令之后,除了會將這個寫命令的協(xié)議內容追加到現(xiàn)有的 AOF 文件之外,還會追加到這個緩存中:

digraph p {    node [style = filled];    edge [style =

server [label = "命令請求"]; current_aof [label = "現(xiàn)有 AOF 文件", shape = box, fillcolor = "#FADCAD"]; aof_rewrite_buf [label = "AOF 重寫緩存", shape = box, fillcolor = "#FADCAD"]; server -> current_aof [label = "命令協(xié)議內容"]; server -> aof_rewrite_buf [label = "命令協(xié)議內容"];}" />

換言之,當子進程在執(zhí)行 AOF 重寫時,主進程需要執(zhí)行以下三個工作:

  1. 處理命令請求。
  2. 將寫命令追加到現(xiàn)有的 AOF 文件中。
  3. 將寫命令追加到 AOF 重寫緩存中。

這樣一來可以保證:

  1. 現(xiàn)有的 AOF 功能會繼續(xù)執(zhí)行,即使在 AOF 重寫期間發(fā)生停機,也不會有任何數(shù)據(jù)丟失。
  2. 所有對數(shù)據(jù)庫進行修改的命令都會被記錄到 AOF 重寫緩存中。

當子進程完成 AOF 重寫之后,它會向父進程發(fā)送一個完成信號,父進程在接到完成信號之后,會調用一個信號處理函數(shù),并完成以下工作:

  1. 將 AOF 重寫緩存中的內容全部寫入到新 AOF 文件中。
  2. 對新的 AOF 文件進行改名,覆蓋原有的 AOF 文件。

當步驟 1 執(zhí)行完畢之后,現(xiàn)有 AOF 文件、新 AOF 文件和數(shù)據(jù)庫三者的狀態(tài)就完全一致了。

當步驟 2 執(zhí)行完畢之后,程序就完成了新舊兩個 AOF 文件的交替。

這個信號處理函數(shù)執(zhí)行完畢之后,主進程就可以繼續(xù)像往常一樣接受命令請求了。在整個 AOF 后臺重寫過程中,只有最后的寫入緩存和改名操作會造成主進程阻塞,在其他時候,AOF 后臺重寫都不會對主進程造成阻塞,這將 AOF 重寫對性能造成的影響降到了最低。

以上就是 AOF 后臺重寫,也即是 BGREWRITEAOF 命令的工作原理。

AOF 后臺重寫的觸發(fā)條件

AOF 重寫可以由用戶通過調用 BGREWRITEAOF 手動觸發(fā)。

另外,服務器在 AOF 功能開啟的情況下,會維持以下三個變量:

  • 記錄當前 AOF 文件大小的變量 aof_current_size 。
  • 記錄最后一次 AOF 重寫之后, AOF 文件大小的變量 aof_rewrite_base_size 。
  • 增長百分比變量 aof_rewrite_perc 。

每次當 serverCron 函數(shù)執(zhí)行時,它都會檢查以下條件是否全部滿足,如果是的話,就會觸發(fā)自動的 AOF 重寫:

  1. 沒有 BGSAVE 命令在進行。
  2. 沒有 BGREWRITEAOF 在進行。
  3. 當前 AOF 文件大小大于 server.aof_rewrite_min_size (默認值為 1 MB)。
  4. 當前 AOF 文件大小和最后一次 AOF 重寫后的大小之間的比率大于等于指定的增長百分比。

默認情況下,增長百分比為 100% ,也即是說,如果前面三個條件都已經(jīng)滿足,并且當前 AOF 文件大小比最后一次 AOF 重寫時的大小要大一倍的話,那么觸發(fā)自動 AOF 重寫。

小結

  • AOF 文件通過保存所有修改數(shù)據(jù)庫的命令來記錄數(shù)據(jù)庫的狀態(tài)。
  • AOF 文件中的所有命令都以 Redis 通訊協(xié)議的格式保存。
  • 不同的 AOF 保存模式對數(shù)據(jù)的安全性、以及 Redis 的性能有很大的影響。
  • AOF 重寫的目的是用更小的體積來保存數(shù)據(jù)庫狀態(tài),整個重寫過程基本上不影響 Redis 主進程處理命令請求。
  • AOF 重寫是一個有歧義的名字,實際的重寫工作是針對數(shù)據(jù)庫的當前值來進行的,程序既不讀寫、也不使用原有的 AOF 文件。
  • AOF 可以由用戶手動觸發(fā),也可以由服務器自動觸發(fā)。


以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號