Redis&持久化存儲
Redis支持的數據類型:
string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
string類型是Redis最基本的數據類型,一個鍵最大能存儲512MB。
hash 是一個鍵值對集合,特別適合用於存儲對象。每個 hash 可以存儲 2的32 - 1次方 鍵值對(40多億)。
list 列表是簡單的字符串列表,按照插入順序進行排序,可以添加一個元素導列表的頭部(左邊)或者尾部(右邊)。
set 集合是string類型的無需集合,通過哈希表實現,添加,刪除,查找的復雜度都是O(1)。若插入相同元素時,第二次的插入將被忽略。
zset 有序集合,也是string類型元素的集合,且不允許重復的成員。
Redis的事務命令:
MULTI:標記一個事務塊的開始。
EXEC:執行所有事務塊內的命令。
DISCARD:取消事務,放棄執行事務塊內的所有命令。
WATCH key[key ...]:監視一個或多個key,若事務在執行這個key之前被其他命令所改動,那麽事務將被打斷。
UNWATCH:取消 WATCH 命令對所有 key 的監視。
舉個栗子:
redis 127.0.0.1:6379> MULTI OK redis 127.0.0.1:6379> SET book-name "Mastering C++ in 21 days" QUEUED redis 127.0.0.1:6379> GET book-name QUEUED redis 127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series" QUEUED redis 127.0.0.1:6379> SMEMBERS tag QUEUED redis 127.0.0.1:6379> EXEC 1) OK 2) "Mastering C++ in 21 days" 3) (integer) 3 4) 1) "Mastering Series" 2) "C++" 3) "Programming"
Redis設置密碼:
第一種方式(修改配置文件) Sudo vim /etc/redis/redis.conf 命令模式搜索requirepass,把註釋掉的那行打開 # requirepass footbared requirepass 123456 第二種方式:直接在redis中設置,只對當前啟動有效 設置密碼:config set requirepass 123456 取消密碼:config set requirepass “”
Redis的存儲機制:
RDB (快照Snapshot)工作原理: 將databases中的key-value的二進制形式存儲在了rdb文件中。先將數據存在內存,然後當數據累計達到某些設定的閥值的時候,就會觸發一次DUMP操作,將變化的數據一次性寫入數據文件(RDB文件)。
AOF 工作原理: 是將數據也是先存在內存,但是在存儲的時候會使用調用fsync來完成對本次寫操作的日誌記錄,這個日誌揭露文件其實是一個基於Redis網絡交互協議的文本文件。AOF調用fsync也不是說全部都是無阻塞的,在某些系統上可能出現fsync阻塞進程的情況,對於這種情況可以通過配置修改,但默認情況不要修改。AOF最關鍵的配置就是關於調用fsync追加日誌文件的平率,有兩種預設頻率,always每次記錄進來都添加,everysecond 每秒添加一次。兩個配置各有所長後面分析。由於是采用日誌追加的方式來持久話數據,所以引出了第二個日誌的概念:rewrite. 後面介紹它的由來。
無論是那種機制,Redis都是將數據存儲在內存中。
性能&安全比較:
性能:
RDB方式的性能明顯高於AOF方式,RDB采用壓縮的二進制方式存儲數據,數據文件比較小,加載快速。存儲的時候是按照配置項中的save策略來存儲,每次都是聚合很多數據批量存儲,寫入的效率很好,而AOF則一般都是工作在實時存儲或者準實時模式下。相對來說存儲的頻率高,效率卻偏低。
數據安全:
AOF數據安全性高於RDB存儲,Snapshot存儲是基於累計批量的思想,也就是在允許的情況下,累計的數據越多那麽寫入效率也就越高,但數據的累計是靠時間的積累完成的,那麽如果在長時間數據不寫入RDB,但Redis又遇到了崩潰,那麽沒有寫入的數據就無法恢復了,但是AOF方式偏偏相反,根據AOF配置的存儲頻率的策略可以做到最少的數據丟失和較高的數據恢復能力。
Redis特點
Redis本質上是一個Key-Value類型的內存數據庫,很像memcached,整個數據庫統統加載在內存當中進行操作,定期通過異步操作把數據庫數據flush到硬盤上進行保存。因為是純內存操作,Redis的性能非常出色,每秒可以處理超過 10萬次讀寫操作,是已知性能最快的Key-Value DB。
Redis的出色之處不僅僅是性能,Redis最大的魅力是支持保存多種數據結構,此外單個value的最大限制是1GB,不像 memcached只能保存1MB的數據,因此Redis可以用來實現很多有用的功能,比方說用他的List來做FIFO雙向鏈表,實現一個輕量級的高性 能消息隊列服務,用他的Set可以做高性能的tag系統等等。另外Redis也可以對存入的Key-Value設置expire時間,因此也可以被當作一 個功能加強版的memcached來用。
Redis的主要缺點是數據庫容量受到物理內存的限制,不能用作海量數據的高性能讀寫,因此Redis適合的場景主要局限在較小數據量的高性能操作和運算上。
Redis持久化方式:
- RDB 持久化(Redis DataBase)可以在指定的時間間隔內生成數據集的時間點快照(point-in-time snapshot)。
- AOF 持久化(Append-only file)記錄服務器執行的所有寫操作命令,並在服務器啟動時,通過重新執行這些命令來還原數據集。 AOF 文件中的命令全部以 Redis 協議的格式來保存,新命令會被追加到文件的末尾。 Redis 還可以在後臺對 AOF 文件進行重寫(rewrite),使得 AOF 文件的體積不會超出保存數據集狀態所需的實際大小。
- Redis 還可以同時使用 AOF 持久化和 RDB 持久化。 在這種情況下, 當 Redis 重啟時, 它會優先使用 AOF 文件來還原數據集, 因為 AOF 文件保存的數據集通常比 RDB 文件所保存的數據集更完整。
RDB 快照
在默認情況下, Redis 將數據庫快照保存在名字為 dump.rdb
的二進制文件中。可以對 Redis 進行設置, 讓它在“ N
秒內數據集至少有 M
個改動”這一條件被滿足時, 自動保存一次數據集。
執行保存操作:調用 SAVE 或者 BGSAVE ,手動讓 Redis 進行數據集保存操作。一個栗子,save 60 1000 會讓 Redis 在滿足“ 60
秒內有至少有 1000
個鍵被改動”這一條件時, 自動保存一次數據集。這種持久化方式被稱為快照(snapshot)。
SAVE
:阻塞redis的服務器進程,直到RDB
文件
被創建完畢。BGSAVE
:派生(fork)一個子進程來創建新的RDB文件
,記錄接收到BGSAVE
當時的數據庫狀態,父進程繼續處理接收到的命令,子進程完成文件的創建之後,會發送信號給父進程,而與此同時,父進程處理命令的同時,通過輪詢來接收子進程的信號。
快照的運作方式
當Redis需要保存 dump.rdb 文件時,執行以下操作:
- Redis 調用
fork()
,同時擁有父進程和子進程。 - 子進程將數據集寫入到一個臨時 RDB 文件中。
- 當子進程完成對新 RDB 文件的寫入時,Redis 用新 RDB 文件替換原來的 RDB 文件,並刪除舊的 RDB 文件。
這種工作方式使得 Redis 可以從寫時復制(copy-on-write)機制中獲益。
RDB 優點
- RDB 是一個非常緊湊(compact)的文件,它保存了 Redis 在某個時間點上的數據集。 這種文件非常適合用於進行備份: 比如說,你可以在最近的 24 小時內,每小時備份一次 RDB 文件,並且在每個月的每一天,也備份一個 RDB 文件。 這樣的話,即使遇上問題,也可以隨時將數據集還原到不同的版本。
- 生成的文件是一種壓縮的二進制文件,方便於在網絡中傳輸。
- RDB 非常適用於災難恢復(disaster recovery):它只有一個文件,並且內容都非常緊湊,可以(在加密後)將它傳送到別的數據中心。
- RDB 可以最大化 Redis 的性能:父進程在保存 RDB 文件時唯一要做的就是
fork
出一個子進程,然後這個子進程就會處理接下來的所有保存工作,父進程無須執行任何磁盤 I/O 操作。 - RDB 在恢復大數據集時的速度比 AOF 的恢復速度要快。
RDB 缺點
- 如果想要避免在服務器故障時丟失數據,那麽 RDB 不太適合。 RDB保存一次備份之後,到下一次保存之前,這段期間所產生的的新數據,如果還沒有達到生成備份文件的條件,此時服務器宕機就會丟失這部分數據。雖然 Redis 允許你設置不同的保存點(save point)來控制保存 RDB 文件的頻率, 但是因為 RDB 文件需要保存整個數據集的狀態,所以它是一個非常耗費系統資源的操作。 因此若是需要至少 5 分鐘才保存一次 RDB 文件的情況下, 一旦發生故障停機,可能會丟失好幾分鐘的數據。
- 每次保存 RDB 的時候,Redis 都要
fork()
創建出一個子進程,並由子進程來進行實際的持久化工作。 在數據集比較龐大時,fork()
可能會非常耗時,造成服務器在某某毫秒內停止處理客戶端; 如果數據集非常巨大,並且 CPU 時間非常緊張的話,那麽這種停止時間甚至可能會長達整整一秒。 雖然 AOF 重寫也需要進行fork()
,但無論 AOF 重寫的執行間隔有多長,數據的耐久性都不會有任何損失。創建子線程和生成rdb文件會占用大量 的系統資源和處理時間
RDB 配置文件
# dbfilename:配置RDB文件的名稱,默認叫 dump.rdb dbfilename dump.rdb # dir:配置的RDB文件存儲在本地的路徑,如果是在 /redis/redis-3.0.6/src 下啟動的redis-cli,則數據會存儲在當前src目錄下 dir ./ # snapshot觸發時機的配置:save <seconds> <changes> , 可通過 save “” 關閉snapshot功能 # changes:對於此值設置需謹慎,要評估系統的變更操作密集程度 save 900 1 # 更改了1個key的時候,間隔900秒後,至少有一個變更操作,進行持久化存儲snapshot save 300 10 # 更改了10個key的時候,間隔300s進行持久化存儲 save 60 10000 # 更改10000個key的時候,間隔360s進行存儲。 # 當生成 RDB 文件出錯無法繼續時,是否則色客戶端的“變更操作”,是否繼續處理 Redis 寫命令,默認為不處理。“錯誤”可能因為磁盤已滿/磁盤故障/OS級別異常等 stop-writes-on-bgsave-error yes # 是否對rdb文件進行壓縮,默認為“yes”,壓縮往往意味著“額外的cpu消耗”,同時也意味這較小的文件尺寸以及較短的 rdbcompression yes
# 是否對 RDB 文件進行校驗和校驗
rdbchecksum
#####
RDB 命令演示
Redis shutdown模擬服務器宕機
mv dump.rdb dump.rdb.bak
停止redis服務器service redis stop
啟動redis-server /etc/redis/redis.conf
redis-cli
查詢keys *
cp dump.rdb.bak dump.rdb
ps aux | grep redis
Kill -9 xxxx
停止redis服務器service redis stop
重啟redis-server
重啟redis-cli
查詢keys *
AOF:只進行追加操作的文件(append-only file)
快照功能並不是非常耐久(durable): 如果 Redis 因為某些原因而造成故障停機, 那麽服務器將丟失最近寫入、且仍未保存到快照中的那些數據。如果對於數據追求完全耐久能力(full durability)的要求,快照功能就不太適用。從 1.1 版本開始, Redis 增加了一種完全耐久的持久化方式: AOF 持久化。
通過修改配置文件來打開 AOF 功能:appendonly yes
每當 Redis 執行一個改變數據集的命令時(比如 SET key value [EX seconds] [PX milliseconds] [NX|XX]), 這個命令就會被追加到 AOF 文件的末尾(對數據的每一條修改命令追加到aof文件)。這樣的話,當 Redis 重新啟時, 程序就可以通過重新執行 AOF 文件中的命令來達到重建數據集的目的。RDB持久化相當於備份數據庫狀態,而AOF持久化是備份數據庫接收到的命令。
AOF文件生成的過程:命令追加、文件寫入、文件同步
AOF 重寫(Rewrite)
因為 AOF 的運作方式是不斷地將命令追加到文件的末尾,按照記錄日誌的方式去工作的,所以隨著寫入命令的不斷增加,成千上萬的數據插入必然導致日誌文件的擴大,AOF 文件的體積也會變得越來越大。舉個栗子如果你對一個計數器調用了 100 次 INCR key , 那麽僅僅是為了保存這個計數器的當前值, AOF 文件就需要使用 100 條記錄(entry)。然而實際上,只使用一條 SET key value [EX seconds] [PX milliseconds] [NX|XX] 命令已經足以保存計數器的當前值了, 其余 99 條記錄實際上都是多余的。
為了處理這種情況, Redis 支持另一種特性:可以在不打斷服務客戶端的情況下,對 AOF 文件進行重建(rebuild):執行 BGREWRITEAOF 命令, Redis 將生成一個新的 AOF 文件, 這個文件包含重建當前數據集所需的最少命令。Redis 2.2 需要自己手動執行 BGREWRITEAOF 命令; Redis 2.4 則可以自動觸發 AOF 重寫。
Redis的功能:
AOF的存儲是,Redis會根據配置項,合理的觸發Rewrite操作,就是將日誌文件中的所有數據都重新寫到另外一個新的日誌文件中,但是不同的是,對於老日誌文件中對於Key的多次操作,只保留最終的值的那次操作記錄到日誌文件中,從而縮小日誌文件的大小。這裏有兩個配置需要註意:
auto-aof-rewrite-percentage 100 (當前寫入日誌文件的大小占到初始日誌文件大小的某個百分比時觸發Rewrite)
auto-aof-rewrite-min-size 64mb (本次Rewrite最小的寫入數據良)
兩個條件需要同時滿足。
AOF 的運作方式
AOF 重寫和 RDB 創建快照一樣,都巧妙地利用了寫時復制機制。
以下是 AOF 重寫的執行步驟:
- Redis 執行
fork()
,現在同時擁有父進程和子進程。 - 子進程開始將新 AOF 文件的內容寫入到臨時文件。
- 對於所有新執行的寫入命令,父進程一邊將它們累積到一個內存緩存中,一邊將這些改動追加到現有 AOF 文件的末尾:這樣即使在重寫的中途發生停機,現有的 AOF 文件也還是安全的。
- 當子進程完成重寫工作時,它給父進程發送一個信號,父進程在接收到信號之後,將內存緩存中的所有數據追加到新 AOF 文件的末尾。
- 搞定!現在 Redis 原子地用新文件替換舊文件,之後所有命令都會直接追加到新 AOF 文件的末尾。
AOF的優點
- 提供了多種同步命令方式,默認1s同步(
fsync
)一次寫命令,就算發生故障停機,最多丟失1s的數據。(fsync
會在後臺線程執行,所以主線程可以繼續努力地處理命令請求)。 - AOF 文件是一個只進行追加操作的日誌文件(append only log), 因此對 AOF 文件的寫入不需要進行查找(
seek)
, 即使日誌因為某些原因而包含了未寫入完整的命令(比如寫入時磁盤已滿,寫入中途停機等),redis-check-aof
工具也可以輕易地修復這種問題。 - Redis 可以在 AOF 文件體積變得過大時,自動地在後臺對 AOF 進行重寫: 重寫後的新 AOF 文件包含了恢復當前數據集所需的最小命令集合。 整個重寫操作是絕對安全的,因為 Redis 在創建新 AOF 文件的過程中,會繼續將命令追加到現有的 AOF 文件裏面,即使重寫過程中發生停機,現有的 AOF 文件也不會丟失。 而一旦新 AOF 文件創建完畢,Redis 就會從舊 AOF 文件切換到新 AOF 文件,並開始對新 AOF 文件進行追加操作。
- AOF 文件有序地保存了對數據庫執行的所有寫入操作,如果你不小心執行了 FLUSHALL 命令,只要 AOF 文件未被重寫,那麽只要停止服務器, 移除 AOF 文件末尾的 FLUSHALL 命令,並重啟 Redis,就可以將數據集恢復到 FLUSHALL 執行之前的狀態。
AOF 的缺點
- 對於相同的數據集來說,AOF 文件的體積通常要大於 RDB 文件的體積。當Redis負載較高時,RDB比AOF性能更好。
- 根據所使用的
fsync
策略,AOF 的速度可能會慢於 RDB 。 在一般情況下, 每秒fsync
的性能依然非常高, 而關閉fsync
可以讓 AOF 的速度和 RDB 一樣快, 即使在高負荷之下也是如此。 不過在處理巨大的寫入載入時,RDB 可以提供更有保證的最大延遲時間(latency)。 - AOF 曾經發生過的 bug :因為個別命令的原因,導致 AOF 文件在重新載入時,無法將數據集恢復成保存時的原樣。(舉個栗子,阻塞命令 BRPOPLPUSH source destination timeout 就曾引起過這樣的 bug)它們會自動生成隨機、復雜的數據集,並通過重新載入這些數據來確保一切正常。雖然這種 bug 在 AOF 文件中並不常見,但是對比來說,RDB 幾乎是不可能出現這種 bug 的。
AOF 配置文件
# 是否打開 AOF 持久化功能,默認為“no”,可通過“yes”來開啟AOF功能 appendonly yes # 只有在“yes”下,aof重寫/文件同步等特性才會生效 # 指定AOF文件的名稱 appendfilename appendonly.aof # 同步頻率:指定AOF操作時,文件的同步策略,有三個合法值:always everysec no,默認為everysec 會影響到服務器間隔多久完成一次命令的記錄。 # always:每一條aof記錄都立即同步到文件,這是最安全的方式,但大量磁盤操作和阻塞延遲造成IO開支大,速度最慢不推薦。 # everysec:將緩存區的內容每隔一秒寫入AOF文件中,性能和安全都比較中庸,是Redis官方推薦的方式。 # no :寫入AOF文件中的操作由操作系統決定,Redis不直接調用。一般而言為了提高效率,操作系統會等待緩存區被填滿,才會開始同步數據到磁盤。在物理服務器故障時,數據丟失量會因OS配置有關 appendfsync everysec # 在aof-rewrite期間,appendfsync是否暫緩文件同步,"no"表示“不暫緩”,“yes”表示“暫緩”,默認為“no” no-appendfsync-on-rewrite no # aof文件rewrite觸發的最小文件尺寸(mb,gb),只有大於此aof文件大於此尺寸是才會觸發rewrite,默認“64mb”,建議“512mb” auto-aof-rewrite-min-size 64mb # 相對於“上一次”rewrite,本次rewrite觸發時aof文件應該增長的百分比。 # 每一次rewrite之後,redis都會記錄下此時“新aof”文件的大小(例如A),那麽當aof文件增長到A*(1 + p)之後,觸發下一次rewrite,每一次aof記錄的添加都會檢測當前aof文件的尺寸。
auto-aof-rewrite-percentage 100
# 當前AOF文件啟動新的日誌重寫過程的最小值,避免剛剛啟動Reids時由於文件尺寸較小導致頻繁的重寫。
auto-aof-rewrite-min-size 64mb
RDB和AOF如何選擇
- AOF更加安全,可以將數據更加及時的同步到文件中,但是AOF需要較多的磁盤IO開支,AOF文件尺寸較大,文件內容恢復數度相對較慢
- RDB(snapshot),安全性較差,它是“正常時期”數據備份以及 master-slave 數據同步的最佳手段,文件尺寸較小,恢復數度較快。
(1)不要僅僅使用RDB,因為那樣會導致你丟失很多數據
(2)也不要僅僅使用AOF,因為那樣有兩個問題,第一,通過AOF做冷備的操作,沒有RDB做冷備來的恢復速度更快; 第二,RDB每次簡單粗暴生成數據快照更加健壯,可以避免AOF這種復雜的備份和恢復機制的bug 。
(3)綜合使用AOF和RDB兩種持久化機制,用AOF來保證數據不丟失,作為數據恢復的第一選擇; 用RDB來做不同程度的冷備,在AOF文件都丟失或損壞不可用的時候,還可以使用RDB來進行快速的數據恢復。
怎麽從 RDB 持久化切換到 AOF 持久化
在 Redis 2.2 或以上版本,可以在不重啟的情況下,從 RDB 切換到 AOF :
- 為最新的
dump.rdb
文件創建一個備份。 - 將備份放到一個安全的地方。
- 執行以下兩條命令:
redis-cli> CONFIG SET appendonly yes
redis-cli> CONFIG SET save ""
- 確保命令執行之後,數據庫的鍵的數量沒有改變。
- 確保寫命令會被正確地追加到 AOF 文件的末尾。
步驟 3 執行的第一條命令開啟了 AOF 功能: Redis 會阻塞直到初始 AOF 文件創建完成為止, 之後 Redis 會繼續處理命令請求, 並開始將寫入命令追加到 AOF 文件末尾。
步驟 3 執行的第二條命令用於關閉 RDB 功能。 這一步是可選的, 如果你願意的話, 也可以同時使用 RDB 和 AOF 這兩種持久化功能。
別忘了在 redis.conf
中打開 AOF 功能! 否則服務器重啟之後, 之前通過 CONFIG SET
設置的配置就會被遺忘, 程序會按原來的配置來啟動服務器。
對比
AOF
更安全,可將數據及時同步到文件中,但需要較多的磁盤IO,AOF文件
尺寸較大,文件內容恢復相對較慢, 也更完整。RDB
持久化,安全性較差,它是正常時期數據備份及master-slave
數據同步的最佳手段,文件尺寸較小,恢復數度較快。
備份 Redis 數據
官方建議:
- 創建一個定期任務(cron job), 每小時將一個 RDB 文件備份到一個文件夾, 並且每天將一個 RDB 文件備份到另一個文件夾。
- 確保快照的備份都帶有相應的日期和時間信息, 每次執行定期任務腳本時, 使用
find
命令來刪除過期的快照: 比如可以保留最近 48 小時內的每小時快照, 還可以保留最近一兩個月的每日快照。 - 至少每天一次, 將 RDB 備份到你的數據中心之外, 或者至少是備份到你運行 Redis 服務器的物理機器之外。
Redis&持久化存儲