1. 程式人生 > 實用技巧 >Error-React.js:Warning: Each child in an array or iterator should have a unique "key" prop.

Error-React.js:Warning: Each child in an array or iterator should have a unique "key" prop.

NoSQL概述

NoSQL = Not Only SQL,非關係型的資料庫。

為什麼需要NoSQL

  1. 高併發讀寫
  2. 海量資料的高效率儲存和訪問
  3. 高可擴充套件性和高可用性

NoSQL資料庫的四大分類

  • 鍵值(key-value)儲存
  • 列儲存
  • 文件資料庫
  • 圖形資料庫

四類NoSQL資料庫的比較

NoSQL資料庫的特點

  • 易擴充套件
  • 大資料量,高效能
  • 靈活的資料模型
  • 高可用

Redis概述

高效能鍵值對資料庫。

支援的鍵值資料型別

  • 字串型別(String)
  • 列表型別(list)
  • 雜湊型別(hash)
  • 集合型別(Set)
  • 有序集合型別(ZSet)

應用場景

  • 快取:最主要的應用場景
  • 任務佇列
  • 網站訪問統計
  • 應用排行榜
  • 資料過期處理
  • 分散式叢集架構中的session分離
  • ...

Redis的安裝和使用

搭建環境

  • 虛擬機器:VMware 10.0.2
  • Linux系統:CentOS-6.5
  • SSH客戶端:SecureCRT 7.3, SecureFX 7.3

如何在Linux(Centos環境)下安裝、啟動和關閉Redis

Jedis入門

Jedis介紹

Jedis的使用

開發工具:IDEA。 新建Maven專案。

在pom.xml檔案引入依賴
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>

<!--後面用到了@Test註解,所以這裡引入junit依賴-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>compile</scope>
</dependency>
測試連線
@Test
public void demo1(){
    //1.設定IP地址和埠
    Jedis jedis = new Jedis("10.3.11.185",6379);
    //2.儲存資料
    jedis.set("name","imooca");
    //3.獲取資料
    String value = jedis.get("name");
    System.out.println(value);
    //4.釋放資源
    jedis.close();
    }
以連線池方式連線
@Test
//以連線池方式連線
public void demo2(){
    //獲得連線池的配置物件
    JedisPoolConfig config = new JedisPoolConfig();

    //設定最大連線數
    config.setMaxTotal(30);

    //設定最大的空閒連線數
    config.setMaxIdle((10));

    //獲得連線池
    JedisPool jedisPool = new JedisPool(config,"10.3.11.185",6379);

    //獲得核心物件
    Jedis jedis = null;
    try {
        //通過連線池獲得連線
        jedis = jedisPool.getResource();

        //設定資料
        jedis.set("name","張三");
        //獲取資料
        String value = jedis.get("name");
        System.out.println(value);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        //釋放資源
        if(jedis != null){
            jedis.close();
        }
        if(jedisPool != null){
            jedisPool.close();
        }
    }
}


Redis的資料結構及其常用命令

五種資料型別:

  • 字串(String)
  • 字串列表(list)
  • 雜湊(hash)
  • 字串集合(set)
  • 有序字串集合(sorted set/ zset)

Redis是高效能鍵值對(key-value)資料庫.

key定義的注意點:
  1. 不要過長:最好不要超過1024個位元組,不然不僅會消耗記憶體,而且會降低查詢的效率
  2. 不要太短:會降低可讀性
  3. 最好要有統一的命名規範
在redis目錄下鍵入# ./bin/redis-cli開啟Redis客戶端,進入命令列輸入模式。

Redis的資料結構之字串

  • 二進位制安全的,存入和獲取的資料相同
  • Value最多可以容納的資料長度是512M
儲存String的常用命令

Redis的資料結構之Hash

  • 可以看成是String key和String value的map容器
  • 每一個Hash可以儲存4294967295個鍵值對
儲存hash的常用命令
  • 賦值:hset key field value, hmset key field1 value1 [field2 value2]
  • 取值: hget key field, hmget key field1 [field2], hgetall key
  • 刪除:hdel key field1 [field2], del key
  • 增加數字:hincrby key field increment, hincrbyfloat key field increment
  • 自學命令: hlen key, hkeys key


Redis的資料結構之list

  • ArrayList使用陣列
  • LinkedList使用雙向連結串列方式
  • 雙向連結串列中增加資料
  • 雙向連結串列中刪除資料
儲存list的常用命令
  • 兩端新增:lpush key value1 [value2], rpush key value1 [value2], lpushx key value, rpushx key value
  • 兩端彈出: lpop key, rpop key, lrem key count value
  • 檢視列表: lrange key start stop
  • 獲取列表中元素個數: llen key
  • 擴充套件命令:rpoplpush source destination 更多請參考(https://www.runoob.com/redis/redis-lists.html)。





rpoplpush命令的使用場景

例如:list1是生產消費佇列,list2常用於備份資料。解決的問題:consumer pop之後,還沒處理完就掛了。解決辦法:consumer pop之後先放到list2,處理完再從list2刪掉。

Redis的資料結構之Set

  • 和List型別不同的是,Set集合中不允許出現重複的元素
  • Set可包含的最大元素數量是4294967295
儲存集合Set的常用命令
  • 新增/刪除元素:sadd key member1 [member2], spop key, srem key member1 [member2]
  • 獲得集合中的元素:scard key, smembers key, srandmember key [count]
  • 集合中的差集運算: sdiff key1 [key2], sdiffstore destination key1 [key2],
  • 集合中的交集運算: sinter key1 [key2], sinterstore destination key1 [key2]
  • 集合中的並集運算: sunion key1 [key2], sunionstore destination key1 [key2]
  • 擴充套件命令: sismember key member, smove source destination member, sscan key cursor [MATCH pattern] [COUNT count]

更多請參考(https://www.runoob.com/redis/redis-sets.html).





Set的使用場景
  • 跟蹤一些唯一性資料:比如說訪問某一部落格的唯一IP地址,只需要存入Set就可以保證唯一性。
  • 用於維護資料物件之間的關聯關係:比如將所有購買所有某一商品的使用者id儲存到一個Set中,將所有購買另一商品的使用者Id儲存到另一Set中,要求同時購買了兩種商品的使用者,只要求兩個Set的交集即可。

Redis的資料結構之Sorted-Set

  • Sorted-Set與Set的區別: 有序集合和集合一樣也是string型別元素的集合,且不允許重複的成員。不同的是每個元素都會關聯一個double型別的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。有序集合的成員是唯一的,但分數(score)卻可以重複。集合是通過雜湊表實現的,所以新增,刪除,查詢的複雜度都是O(1)。 集合中最大的成員數為4294967295。
  • Sorted-Set中的成員在集合中的位置是有序的
儲存Sorted-Set的常用命令
  • 新增元素:zadd key score1 member1 [score2 member2],
  • 刪除元素:zrem key member [member...], zremrangebylex key min max, zremrangebyrank key start stop, zremrangebyscore key start stop
  • 獲得元素: zcard key, zrevrange key start stop[withscores]
  • 範圍查詢:zcount key min max,
  • 擴充套件命令:zscore key member, zrevrank key member, zrank ket member

詳細請參考(https://www.runoob.com/redis/redis-sorted-sets.html)。





Sorted-Set的使用場景
  • 如大型線上遊戲積分排行榜,分數變化可以用zadd命令更新,用zrange命令獲取排行榜

Redis中Keys的通用操作

  • keys * 查詢所有Key
  • keys my? 查詢以my開頭的Key
  • del my1 my2 my3 刪除my1 my2 my3
  • exists my1 檢視Key是否存在
  • rename key1 key2 重新命名key1為key2
  • expire key1 1000 為KEY設定過期時間

更多命令請檢視(https://www.runoob.com/redis/redis-keys.html).


Redis的特性

  1. 多資料庫:最多支援16個數據庫,下標從0-15,預設為0號庫。

  2. Redis事務
    事務中,所有命令都會序列執行,事務執行期間,redis不會為其它的客戶端提供服務,從而保證命令原子化執行。單個Redis命令的執行是原子性的,但Redis沒有在事務上增加任何維持原子性的機制,因此Redis事務的執行並不是原子性的

事務可以理解為一個打包的批量執行指令碼,但批量執行指令碼並非原子化的操作,中間某條指令的失敗並不會導致前面已做的指令的回滾,也不會造成後續的指令不做。

Redis事務的命令:

  • discard:回滾事務,放棄執行事務塊內的所有命令
  • exec:執行所有事務塊內的命令,執行事務(提交事務)
  • multi:標記一個事務塊的開始,即開啟事務
  • unwatch:取消watch命令對所有key的監視
  • watch key [key ...]:監視一個(或多個)key,如果在事務執行之前這個(或這些)事務被其他命令所改動,那麼事務將被打斷。

Redis的持久化

持久化使用的方式:

  • RDB持久化:將當前程序中的資料生成快照儲存到硬碟中(因此也被稱為快照持久化),儲存的檔案字尾是rdb;當Redis重新啟動時,可以讀取快照檔案恢復資料
  • AOF持久化:RDB是將程序資料寫入檔案,而AOF持久化(即Append Only File持久化),則是將Redis執行的每次寫命令記錄到單獨的日誌檔案中(有點像M有SQL的binlog);當Redis重啟時再次執行AOF檔案中的命令來恢復資料。
  • 無持久化
  • 同時使用RDB和AOF

與RDB相比,AOF的實時性更好,因此已經成為主流的持久化方案。

RDB持久化方式

1. 觸發條件

RDB持久化的觸發分為手動觸發和自動觸發兩種。

(1)手動觸發

save命令和bgsave命令都可以生成RDB檔案。
save命令會阻塞Redis伺服器程序,直到RDB檔案建立完畢為止,在Redis伺服器阻塞期間,伺服器不能處理任何命令請求。

而bgsave命令會建立一個子程序,由子程序來負責建立RDB檔案,父程序(即Redis主程序)則繼續處理請求。

此時伺服器執行日誌如下:

bgsave命令執行過程中,只有fork子程序時會阻塞伺服器,而對於save命令,整個過程都會阻塞伺服器,因此save已基本被廢棄,線上環境要杜絕save的使用;後文中也將只介紹bgsave命令。此外,在自動觸發RDB持久化時,Redis也會選擇bgsave而不是save來進行持久化;下面介紹自動觸發RDB持久化的條件。

(2)自動觸發

save m n
自動觸發最常見的情況是在配置檔案中通過save m n,指定當m秒內發生n次變化時,會觸發bgsave。

例如,檢視redis的預設配置檔案(Linux下為redis根目錄下的redis.conf),可以看到如下配置資訊:

其中save 900 1的含義是:當時間到900秒時,如果redis資料發生了至少1次變化,則執行bgsave;save 300 10save 60 10000同理。當三個save條件滿足任意一個時,都會引起bgsave的呼叫。

save m n的實現原理:

Redis的save m n,是通過serverCron函式、dirty計數器、和lastsave時間戳來實現的。

serverCron是Redis伺服器的週期性操作函式,預設每隔100ms執行一次;該函式對伺服器的狀態進行維護,其中一項工作就是檢查 save m n配置的條件是否滿足,如果滿足就執行bgsave。

dirty計數器是Redis伺服器維持的一個狀態,記錄了上一次執行bgsave/save命令後,伺服器狀態進行了多少次修改(包括增刪改);而當save/bgsave執行完成後,會將dirty重新置為0。

例如,如果Redis執行了set mykey helloworld,則dirty值會+1;如果執行了sadd myset v1 v2 v3,則dirty值會+3;注意dirty記錄的是伺服器進行了多少次修改,而不是客戶端執行了多少修改資料的命令。

lastsave時間戳也是Redis伺服器維持的一個狀態,記錄的是上一次成功執行save/bgsave的時間。

save m n的原理如下:每隔100ms,執行serverCron函式;在serverCron函式中,遍歷save m n配置的儲存條件,只要有一個條件滿足,就進行bgsave。對於每一個save m n條件,只有下面兩條同時滿足時才算滿足:
(1)當前時間-lastsave > m
(2)dirty >= n

其他自動觸發機制:

除了save m n 以外,還有一些其他情況會觸發bgsave:

  • 在主從複製場景下,如果從節點執行全量複製操作,則主節點會執行bgsave命令,並將rdb檔案傳送給從節點
  • 執行shutdown命令時,自動執行rdb持久化,如下圖所示:
2. 執行流程

前面介紹了觸發bgsave的條件,下面將說明bgsave命令的執行流程,如下圖所示:

圖片中的5個步驟所進行的操作如下:

  1. Redis父程序首先判斷:當前是否在執行save,或bgsave/bgrewriteaof(後面會詳細介紹該命令)的子程序,如果在執行則bgsave命令直接返回。bgsave/bgrewriteaof 的子程序不能同時執行,主要是基於效能方面的考慮:兩個併發的子程序同時執行大量的磁碟寫操作,可能引起嚴重的效能問題。
  2. 父程序執行fork操作建立子程序,這個過程中父程序是阻塞的,Redis不能執行來自客戶端的任何命令
  3. 父程序fork後,bgsave命令返回”Background saving started”資訊並不再阻塞父程序,並可以響應其他命令
  4. 子程序建立RDB檔案,根據父程序記憶體快照生成臨時快照檔案,完成後對原有檔案進行原子替換
  5. 子程序傳送訊號給父程序表示完成,父程序更新統計資訊
3. RDB檔案

RDB檔案是經過壓縮的二進位制檔案,下面介紹關於RDB檔案的一些細節。

儲存路徑

RDB檔案的儲存路徑既可以在啟動前配置,也可以通過命令動態設定。

配置:dir配置指定目錄,dbfilename指定檔名。預設是Redis根目錄下的dump.rdb檔案。

動態設定:Redis啟動後也可以動態修改RDB儲存路徑,在磁碟損害或空間不足時非常有用;執行命令為config set dir {newdir}和config set dbfilename {newFileName}。如下所示(Windows環境):

RDB檔案格式
RDB檔案格式如下圖所示(圖片來源:《Redis設計與實現》):

其中各個欄位的含義說明如下:

  1. REDIS:常量,儲存著”REDIS”5個字元。
  2. db_version:RDB檔案的版本號,注意不是Redis的版本號。
  3. SELECTDB 0 pairs:表示一個完整的資料庫(0號資料庫),同理SELECTDB 3 pairs表示完整的3號資料庫;只有當資料庫中有鍵值對時,RDB檔案中才會有該資料庫的資訊(上圖所示的Redis中只有0號和3號資料庫有鍵值對);如果Redis中所有的資料庫都沒有鍵值對,則這一部分直接省略。其中:SELECTDB是一個常量,代表後面跟著的是資料庫號碼;0和3是資料庫號碼;pairs則儲存了具體的鍵值對資訊,包括key、value值,及其資料型別、內部編碼、過期時間、壓縮資訊等等。
  4. EOF:常量,標誌RDB檔案正文內容結束。
  5. check_sum:前面所有內容的校驗和;Redis在載入RBD檔案時,會計算前面的校驗和並與check_sum值比較,判斷檔案是否損壞。

壓縮
Redis預設採用LZF演算法對RDB檔案進行壓縮。雖然壓縮耗時,但是可以大大減小RDB檔案的體積,因此壓縮預設開啟;可以通過命令關閉:

需要注意的是,RDB檔案的壓縮並不是針對整個檔案進行的,而是對資料庫中的字串進行的,且只有在字串達到一定長度(20位元組)時才會進行。

4. 啟動時載入

RDB檔案的載入工作是在伺服器啟動時自動執行的,並沒有專門的命令。但是由於AOF的優先順序更高,因此當AOF開啟時,Redis會優先載入AOF檔案來恢復資料;只有當AOF關閉時,才會在Redis伺服器啟動時檢測RDB檔案,並自動載入。伺服器載入RDB檔案期間處於阻塞狀態,直到載入完成為止。

Redis啟動日誌中可以看到自動載入的執行:

Redis載入RDB檔案時,會對RDB檔案進行校驗,如果檔案損壞,則日誌中會列印錯誤,Redis啟動失敗。

5. RDB常用配置總結

下面是RDB常用的配置項,以及預設值;前面介紹過的這裡不再詳細介紹。

  • save m n:bgsave自動觸發的條件;如果沒有save m n配置,相當於自動的RDB持久化關閉,不過此時仍可以通過其他方式觸發
  • stop-writes-on-bgsave-error yes:當bgsave出現錯誤時,Redis是否停止執行寫命令;設定為yes,則當硬碟出現問題時,可以及時發現,避免資料的大量丟失;設定為no,則Redis無視bgsave的錯誤繼續執行寫命令,當對Redis伺服器的系統(尤其是硬碟)使用了監控時,該選項考慮設定為no
  • rdbcompression yes:是否開啟RDB檔案壓縮
  • rdbchecksum yes:是否開啟RDB檔案的校驗,在寫入檔案和讀取檔案時都起作用;關閉checksum在寫入檔案和啟動檔案時大約能帶來10%的效能提升,但是資料損壞時無法發現
  • dbfilename dump.rdb:RDB檔名
  • dir ./:RDB檔案和AOF檔案所在目錄

AOF持久化方式

1. 開啟AOF

Redis伺服器預設開啟RDB,關閉AOF;要開啟AOF,需要在配置檔案中配置:appendonly yes

2. 執行流程

由於需要記錄Redis的每條寫命令,因此AOF不需要觸發,下面介紹AOF的執行流程。
AOF的執行流程包括:

  • 命令追加(append):將Redis的寫命令追加到緩衝區aof_buf;
  • 檔案寫入(write)和檔案同步(sync):根據不同的同步策略將aof_buf中的內容同步到硬碟;
  • 檔案重寫(rewrite):定期重寫AOF檔案,達到壓縮的目的。

(1)命令追加(append)
Redis先將寫命令追加到緩衝區,而不是直接寫入檔案,主要是為了避免每次有寫命令都直接寫入硬碟,導致硬碟IO成為Redis負載的瓶頸。

命令追加的格式是Redis命令請求的協議格式,它是一種純文字格式,具有相容性好、可讀性強、容易處理、操作簡單避免二次開銷等優點;具體格式略。在AOF檔案中,除了用於指定資料庫的select命令(如select 0 為選中0號資料庫)是由Redis新增的,其他都是客戶端傳送來的寫命令。

(2)檔案寫入(write)和檔案同步(sync)
Redis提供了多種AOF快取區的同步檔案策略,策略涉及到作業系統的write函式和fsync函式,說明如下:

為了提高檔案寫入效率,在現代作業系統中,當用戶呼叫write函式將資料寫入檔案時,作業系統通常會將資料暫存到一個記憶體緩衝區裡,當緩衝區被填滿或超過了指定時限後,才真正將緩衝區的資料寫入到硬盤裡。這樣的操作雖然提高了效率,但也帶來了安全問題:如果計算機停機,記憶體緩衝區中的資料會丟失;因此係統同時提供了fsync、fdatasync等同步函式,可以強制作業系統立刻將緩衝區中的資料寫入到硬盤裡,從而確保資料的安全性。

AOF快取區的同步檔案策略由引數appendfsync控制,各個值的含義如下:

  • always:命令寫入aof_buf後立即呼叫系統fsync操作同步到AOF檔案,fsync完成後執行緒返回。這種情況下,每次有寫命令都要同步到AOF檔案,硬碟IO成為效能瓶頸,Redis只能支援大約幾百TPS寫入,嚴重降低了Redis的效能;即便是使用固態硬碟(SSD),每秒大約也只能處理幾萬個命令,而且會大大降低SSD的壽命。
  • no:命令寫入aof_buf後呼叫系統write操作,不對AOF檔案做fsync同步;同步由作業系統負責,通常同步週期為30秒。這種情況下,檔案同步的時間不可控,且緩衝區中堆積的資料會很多,資料安全性無法保證。
  • everysec:命令寫入aof_buf後呼叫系統write操作,write完成後執行緒返回;fsync同步檔案操作由專門的執行緒每秒呼叫一次。everysec是前述兩種策略的折中,是效能和資料安全性的平衡,因此是Redis的預設配置,也是我們推薦的配置

(3)檔案重寫(rewrite)
隨著時間流逝,Redis伺服器執行的寫命令越來越多,AOF檔案也會越來越大;過大的AOF檔案不僅會影響伺服器的正常執行,也會導致資料恢復需要的時間過長。

檔案重寫是指定期重寫AOF檔案,減小AOF檔案的體積。需要注意的是,AOF重寫是把Redis程序內的資料轉化為寫命令,同步到新的AOF檔案;不會對舊的AOF檔案進行任何讀取、寫入操作!

關於檔案重寫需要注意的另一點是:對於AOF持久化來說,檔案重寫雖然是強烈推薦的,但並不是必須的;即使沒有檔案重寫,資料也可以被持久化並在Redis啟動的時候匯入;因此在一些實現中,會關閉自動的檔案重寫,然後通過定時任務在每天的某一時刻定時執行。

檔案重寫之所以能夠壓縮AOF檔案,原因在於:

  • 過期的資料不再寫入檔案
  • 無效的命令不再寫入檔案:如有些資料被重複設值(set mykey v1, set mykey v2)、有些資料被刪除了(sadd myset v1, del myset)等等
  • 多條命令可以合併為一個:如sadd myset v1, sadd myset v2, sadd myset v3可以合併為sadd myset v1 v2 v3。不過為了防止單條命令過大造成客戶端緩衝區溢位,對於list、set、hash、zset型別的key,並不一定只使用一條命令;而是以某個常量為界將命令拆分為多條。這個常量在redis.h/REDIS_AOF_REWRITE_ITEMS_PER_CMD中定義,不可更改,3.0版本中值是64。

通過上述內容可以看出,由於重寫後AOF執行的命令減少了,檔案重寫既可以減少檔案佔用的空間,也可以加快恢復速度。

檔案重寫的觸發

檔案重寫的觸發,分為手動觸發和自動觸發:

手動觸發:直接呼叫bgrewriteaof命令,該命令的執行與bgsave有些類似:都是fork子程序進行具體的工作,且都只有在fork時阻塞。

此時伺服器執行日誌如下:

自動觸發:根據auto-aof-rewrite-min-size和auto-aof-rewrite-percentage引數,以及aof_current_size和aof_base_size狀態確定觸發時機。

  • auto-aof-rewrite-min-size:執行AOF重寫時,檔案的最小體積,預設值為64MB。
  • auto-aof-rewrite-percentage:執行AOF重寫時,當前AOF大小(即aof_current_size)和上一次重寫時AOF大小(aof_base_size)的比值。
    其中,引數可以通過config get命令檢視:

狀態可以通過info persistence檢視:

只有當auto-aof-rewrite-min-sizeauto-aof-rewrite-percentage兩個引數同時滿足時,才會自動觸發AOF重寫,即bgrewriteaof操作。
自動觸發bgrewriteaof時,可以看到伺服器日誌如下:

檔案重寫的流程

檔案重寫流程如下圖所示(圖片來源:http://www.cnblogs.com/yangmingxianshen/p/8373205.html):

關於檔案重寫的流程,有兩點需要特別注意:(1)重寫由父程序fork子程序進行;(2)重寫期間Redis執行的寫命令,需要追加到新的AOF檔案中,為此Redis引入了aof_rewrite_buf快取。

對照上圖,檔案重寫的流程如下:

  1. Redis父程序首先判斷當前是否存在正在執行 bgsave/bgrewriteaof的子程序,如果存在則bgrewriteaof命令直接返回,如果存在bgsave命令則等bgsave執行完成後再執行。前面曾介紹過,這個主要是基於效能方面的考慮。
  2. 父程序執行fork操作建立子程序,這個過程中父程序是阻塞的。
    3.1. 父程序fork後,bgrewriteaof命令返回”Background append only file rewrite started”資訊並不再阻塞父程序,並可以響應其他命令。Redis的所有寫命令依然寫入AOF緩衝區,並根據appendfsync策略同步到硬碟,保證原有AOF機制的正確
    3.2. 由於fork操作使用寫時複製技術,子程序只能共享fork操作時的記憶體資料。由於父程序依然在響應命令,因此Redis使用AOF重寫緩衝區(圖中的aof_rewrite_buf)儲存這部分資料,防止新AOF檔案生成期間丟失這部分資料。也就是說,bgrewriteaof執行期間,Redis的寫命令同時追加到aof_bufaof_rewirte_buf兩個緩衝區
  3. 子程序根據記憶體快照,按照命令合併規則寫入到新的AOF檔案。
    5.1. 子程序寫完新的AOF檔案後,向父程序發訊號,父程序更新統計資訊,具體可以通過info persistence檢視。
    5.2. 父程序把AOF重寫緩衝區的資料寫入到新的AOF檔案,這樣就保證了新AOF檔案所儲存的資料庫狀態和伺服器當前狀態一致。
    5.3. 使用新的AOF檔案替換老檔案,完成AOF重寫。
3. 啟動時載入

前面提到過,當AOF開啟時,Redis啟動時會優先載入AOF檔案來恢復資料;只有當AOF關閉時,才會載入RDB檔案恢復資料。

當AOF開啟,且AOF檔案存在時,Redis啟動日誌:

當AOF開啟,但AOF檔案不存在時,即使RDB檔案存在也不會載入(更早的一些版本可能會載入,但3.0不會),Redis啟動日誌如下:

檔案校驗

與載入RDB檔案類似,Redis載入AOF檔案時,會對AOF檔案進行校驗,如果檔案損壞,則日誌中會列印錯誤,Redis啟動失敗。但如果是AOF檔案結尾不完整(機器突然宕機等容易導致檔案尾部不完整),且aof-load-truncated引數開啟,則日誌中會輸出警告,Redis忽略掉AOF檔案的尾部,啟動成功。aof-load-truncated引數預設是開啟的:

偽客戶端

因為Redis的命令只能在客戶端上下文中執行,而載入AOF檔案時命令是直接從檔案中讀取的,並不是由客戶端傳送;因此Redis伺服器在載入AOF檔案之前,會建立一個沒有網路連線的客戶端,之後用它來執行AOF檔案中的命令,命令執行的效果與帶網路連線的客戶端完全一樣。

4. AOF常用配置總結

下面是AOF常用的配置項,以及預設值;前面介紹過的這裡不再詳細介紹。

  • appendonly no:是否開啟AOF
  • appendfilename "appendonly.aof":AOF檔名
  • dir ./:RDB檔案和AOF檔案所在目錄
  • appendfsync everysec:fsync持久化策略
  • no-appendfsync-on-rewrite no:AOF重寫期間是否禁止fsync;如果開啟該選項,可以減輕檔案重寫時CPU和硬碟的負載(尤其是硬碟),但是可能會丟失AOF重寫期間的資料;需要在負載和安全性之間進行平衡
  • auto-aof-rewrite-percentage 100:檔案重寫觸發條件之一
  • auto-aof-rewrite-min-size 64mb:檔案重寫觸發提交之一
  • aof-load-truncated yes:如果AOF檔案結尾損壞,Redis啟動時是否仍載入AOF檔案

RDB和AOF的優缺點比較

  1. RDB持久化
  • 優點:RDB檔案緊湊,體積小,網路傳輸快,適合全量複製;恢復速度比AOF快很多。當然,與AOF相比,RDB最重要的優點之一是對效能的影響相對較小。
  • 缺點:RDB檔案的致命缺點在於其資料快照的持久化方式決定了必然做不到實時持久化,而在資料越來越重要的今天,資料的大量丟失很多時候是無法接受的,因此AOF持久化成為主流。此外,RDB檔案需要滿足特定格式,相容性差(如老版本的Redis不相容新版本的RDB檔案)。
  1. AOF持久化
    與RDB持久化相對應,AOF的優點在於支援秒級持久化、相容性好,能帶來更高的資料安全性,缺點是檔案大、恢復速度慢、對效能影響大。

總結

本文講述了Redis的安裝和使用,Jedis的入門,Redis的資料結構及其命令以及Redis的持久化等內容。還有Redis主從複製、哨兵、叢集等Redis進階內容,學完再更。