redis源碼分析(四)--aof持久化

Redis aof持久化

  Redis支持兩種持久化方式:rdb與aof,上一篇文章中已經大體介紹了rdb的持久化實現,這篇文章主要介紹aof實現。redis

  與rdb方式相比,aof會使用更多的存儲空間,由於它將數據以客戶端命令的形式進行存儲,並使用ascii編碼。但它也有相應的優勢,如支持append的方式保存db內容的變更,不須要像rdb方式同樣一旦內容有變更,便須要從新完整生成文件才能將變更保存到文件中;同時在子進程持久化的過程當中,能夠累積客戶端的命令到緩存中,最後將緩存內容添加到持久化生成的文件的末尾,幾乎能夠實現不丟失內容的持久化。緩存

1. aof命令格式

aof的持久化方式不只能夠將client端發送來的命令直接添加到aof文件的末尾,還能夠將內存中的數據重寫爲命令的形式。redis中定義aof中的一條完整命令格式以下:app

*count\r\n{$len\r\ncontent\r\n}

以*開頭,後面接這條命令中的參數數目count,並以\r\n結束;後面的每個參數都以$開頭,接參數長度len,並以\r\n結束,後面跟實際的參數內容,並以\r\n結束。函數

舉例,命令RPUSH 「key1」 1 2 3 4這條命令在aof文件中的表示以下:編碼

*6\r\n$5\r\nRPUSH\r\n$4\r\nkey1\r\n\$1\r\n1\r\n$1\r\n2\r\n$1\r\n3\r\n$1\r\n4\r\n

這表示命令中有6個參數,第1個參數長度爲5,值爲RPUSH,第2個參數長度爲4,值爲key1,以此類推。spa

而命令 set 「key2」 「hello, world」這條命令在aof文件中表示以下:code

*3\r\n$3\r\nset\r\n$4\r\nkey2\r\n$12\r\nhello, world\r\n

2. db中的數據rewrite

對於已經存儲在db中的數據,若是須要以aof的方式進行持久化,那麼須要將其重寫爲命令的形式,這個功能經過aof.c源文件中的rewriteAppendOnlyFileRio函數實現。它會遍歷全部的db字典,並遍歷每個字典中的全部key-value對,進行rewrite。重寫規則大體以下:server

  1. 遍歷每個db,首先添加一條命令"*2\r\n$6\r\nSELECT\r\n$len\r\nj\r\n",其中的len爲db索引的字符串形式的長度,j爲其字符串表示,每個db僅在遍歷重寫它的key-value對以前添加該命令。
  2.  遍歷每一對key-value對,根據其類型,添加正確的命令頭,一條命令儘量多的添加數據,但一條命令中參數個數有限制,超過限制則拆分爲多條命令。

舉例,若是內存中存在一個」name1」 「faker」的key-value對,重寫命令以下:blog

*3\r\n$3\r\nset\r\n$5\r\nname\r\n$5\r\nfaker\r\n

若是內存中存在一個list,key爲」key1」,內容爲1 2 3 4,那麼其重寫後的命令以下:索引

*6\r\n$5\r\nRPUSH\r\n$4\r\nkey1\r\n\$1\r\n1\r\n$1\r\n2\r\n$1\r\n3\r\n$1\r\n4\r\n

3. 命令緩存

  redis中aof持久化使用到了兩類緩存,一類緩存用於在子進程運行過程當中,保存客戶端的命令,它是server全局結構的一個list成員aof_rewrite_buf_blocks,該list的節點值類型爲

typedef struct aofrwblock {
    unsigned long used, free;
    char buf[AOF_RW_BUF_BLOCK_SIZE];
} aofrwblock;

當須要將命令保存到aof文件中,而此時server.aof_child_pid != -1(即aof子進程正在運行),命令被添加到aof_rewrite_buf_blocks連接的緩存中。

  這個buffer中的數據會經過pipe發送給子進程,發送函數爲aofChildWriteDiffData,這個函數在pipe的寫事件發生時調用。相應的子進程中會有從pipe接收這些緩存數據的函數aofReadDiffFromParent,這個函數在子進程持久化數據的過程當中被主動調用,並將接收的數據保存到server. aof_child_diff中,在內存數據處理完成後,添加到aof文件末尾。

  另外一類緩存是server.aof_buf,這是一個sds類型的緩存,它在aof持久化開啓,而且沒有aof子進程運行時使用,客戶端命令始終首先保存到該緩存中,而後週期性將該緩存添加到aof文件中。

  經過緩存命令的方式,保證了aof持久化不會丟失更新。

4. aof建立流程

  一個aof持久化文件的完整建立流程以下:

  1. rewriteAppendOnlyFileBackground啓動子進程將db字典中的數據持久化,即便是以aof方式持久化,仍然能夠選擇將此時db字典中的數據以rdb的方式進行存儲,這部分數據恢復時固然也是調用rdb相應函數。
  2. 等待db字典中的數據持久化完成,將持久化過程當中子進程接收的aof_child_diff添加到aof文件的末尾。
  3. 父進程將仍未發送給子進程的aof_rewrite_buf_blocks中的累計更新添加到aof文件末尾。初始化server.aof_buf緩存。
  4. 客戶端命令被緩存到server.aof_buf末尾,並按期更新到aof文件中。

  生成一個有效的aof文件後,後續db字典中的數據有變更時,只須要將相應的命令添加到aof文件末尾,便可完成相應的持久化,不須要像rdb同樣爲了保存新的改動,必須從新完整地對db字典進行處理。

  aof文件的載入一樣相對簡單,按行讀取,從*後獲得參數數目,而後讀取指定數目的參數後,執行命令。

相關文章
相關標籤/搜索