redis持久化

5. redis持久化

Redis 提供了多種不同級別的持久化方式:

  • RDB 持久化可以在指定的時間間隔內生成數據集的時間點快照(point-in-time snapshot)。
  • AOF (Append-only file)持久化記錄服務器執行的所有寫操作命令,並在服務器啟動時,通過重新執行這些命令來還原數據集。AOF 文 件中的命令全部以 Redis 協議的格式來保存,新命令會被追加到文 件的末尾。Redis 還可以在後臺對 AOF 文件進行重寫(rewrite), 使得 AOF 文件的體積不會超出保存數據集狀態所需的實際大小。
  • Redis 還可以同時使用 AOF 持久化和 RDB 持久化。在這種情況下, 當 Redis 重啟時, 它會優先使用 AOF 文件來還原數據集, 因為AOF 文件保存的數據集通常比 RDB 文件所保存的數據集更完整。
  • 你甚至可以關閉持久化功能,讓數據只在服務器運行時存在。

5.1 rdb

5.1.1 save策略

SNAPSHOTTING的持久化方式有多種save策略可供選擇,而且支持混用,例如:

<code>save 900 1
save 300 100
save 60  10000/<code>

上述配置的效果是:snapshotting會在3個條件中的任何一個滿足時被觸發


a. 900s內至少1個key有變化;

b. 300s內至少100個key有變化;

c. 60s內至少有10000個key有變化

  • 主動備份數據
<code>redis 127.0.0.1:6379> SAVE
OK
# 在後臺執行備份
127.0.0.1:6379> BGSAVE
Background saving started/<code>


5.1.2 優缺點

RDB 的優點:

  • RDB是一種表示某個即時點的Redis數據的緊湊文件。RDB文件適合用於備份。例如,你可能想要每小時歸檔最近24小時的RDB文件,每天保存近30天的RDB快照。這允許你很容易的恢復不同版本的數據集以容災。
  • RDB非常適合於災難恢復,作為一個緊湊的單一文件,可以被傳輸到遠程的數據中心,或者是Amazon S3(可能得加密)。
  • RDB最大化了Redis的性能,因為Redis父進程持久化時唯一需要做的是啟動(fork)一個子進程,由子進程完成所有剩餘工作。父進程實例不需要執行像磁盤IO這樣的操作。
  • RDB在重啟保存了大數據集的實例時比AOF要快。

RDB 的缺點

  • 當你需要在Redis停止工作(例如停電)時最小化數據丟失,RDB可能不太好。你可以配置不同的保存點(save point)來保存RDB文件(例如,至少5分鐘和對數據集100次寫之後,但是你可以有多個保存點)。然而,你通常每隔5分鐘或更久創建一個RDB快照,所以一旦Redis因為任何原因沒有正確關閉而停止工作,你就得做好最近幾分鐘數據丟失的準備了。
  • RDB需要經常調用fork()子進程來持久化到磁盤。如果數據集很大的話,fork()比較耗時,結果就是,當數據集非常大並且CPU性能不夠強大的話,Redis會停止服務客戶端幾毫秒甚至一秒。AOF也需要fork(),但是你可以調整多久頻率重寫日誌而不會有損(trade-off)持久性(durability)。

5.2 aof

5.2.1 配置aof

<code>appendonly yes

appendfilename "6379.aof"

appendfsync everysec/<code>

配置說明:

no:redis不主動調用fsync,何時刷盤由os來調度

always:redis針對每個寫入命令俊輝主動調用fsync刷磁盤

eversec:每秒調用一次fsync刷盤

5.2.2 優缺點

AOF 的優點:

  • 使用AOF Redis會更具有可持久性(durable):你可以有很多不同的fsync策略:沒有fsync,每秒fsync,每次請求時fsync。使用默認的每秒fsync策略,寫性能也仍然很不錯(fsync是由後臺線程完成的,主線程繼續努力地執行寫請求),即便你也就僅僅只損失一秒鐘的寫數據。
  • AOF日誌是一個追加文件,所以不需要定位,在斷電時也沒有損壞問題。即使由於某種原因文件末尾是一個寫到一半的命令(磁盤滿或者其他原因),redis-check-aof工具也可以很輕易的修復。
  • 當AOF文件變得很大時,Redis會自動在後臺進行重寫。重寫是絕對安全的,因為Redis繼續往舊的文件中追加,使用創建當前數據集所需的最小操作集合來創建一個全新的文件,一旦第二個文件創建完畢,Redis就會切換這兩個文件,並開始往新文件追加。
  • AOF文件裡面包含一個接一個的操作,以易於理解和解析的格式存儲。你也可以輕易的導出一個AOF文件。例如,即使你不小心錯誤地使用FLUSHALL命令清空一切,如果此時並沒有執行重寫,你仍然可以保存你的數據集,你只要停止服務器,刪除最後一條命令,然後重啟Redis就可以。

AOF 的缺點:

  • 對同樣的數據集,AOF文件通常要大於等價的RDB文件。
  • AOF可能比RDB慢,這取決於準確的fsync策略。通常fsync設置為每秒一次的話性能仍然很高,如果關閉fsync,即使在很高的負載下也和RDB一樣的快。不過,即使在很大的寫負載情況下,RDB還是能提供能好的最大延遲保證。
  • 在過去,我們經歷了一些針對特殊命令(例如,像BRPOPLPUSH這樣的阻塞命令)的罕見bug,導致在數據加載時無法恢復到保存時的樣子。這些bug很罕見,我們也在測試套件中進行了測試,自動隨機創造複雜的數據集,然後加載它們以檢查一切是否正常,但是,這類bug幾乎不可能出現在RDB持久化中。為了說得更清楚一點:Redis AOF是通過遞增地更新一個已經存在的狀態,像MySQL或者MongoDB一樣,而RDB快照是一次又一次地從頭開始創造一切,概念上更健壯。但是,1)要注意Redis每次重寫AOF時都是以當前數據集中的真實數據從頭開始,相對於一直追加的AOF文件(或者一次重寫讀取老的AOF文件而不是讀內存中的數據)對bug的免疫力更強。2)我們還沒有收到一份用戶在真實世界中檢測到崩潰的報告。

5.2.3 AOF持久性如何?

你可以配置 Redis 多久才將數據 fsync 到磁盤一次。有三個選項:

  • 每次有新命令追加到 AOF 文件時就執行一次 fsync :非常慢,也非常安全。
  • 每秒 fsync 一次:足夠快(和使用 RDB 持久化差不多),並且在故障時只會丟失 1 秒鐘的數據。
  • 從不 fsync :將數據交給操作系統來處理。更快,也更不安全的選擇。

推薦(並且也是默認)的措施為每秒 fsync 一次, 這種 fsync 策略可以兼顧速度和安全性。總是 fsync 的策略在實際使用中非常慢, 即使在 Redis 2.0 對相關的程序進行了改進之後仍是如此 —— 頻繁調用 fsync 註定了這種策略不可能快得起來。

6. redis事務

Redis 對事務的支持目前還比較簡單。redis 只能保證一個 client 發起 的事務中的命令可以連續的執行,而中間不會插入其他 client 的命令。由 於 redis 是單線程來處理所有 client 的請求的所以做到這點是很容易的。一般情況下 redis 在接受到一個 client 發來的命令後會立即處理並 返回 處理結果,但是當一個 client 在一個連接中發出 multi 命令有,這個連接 會進入一個事務上下文,該連接後續的命令並不是立即執行,而是先放 到一個隊列中。當從此連接受到 exec 命令後,redis 會順序的執行隊列中 的所有命令。並將所有命令的運行結果打包到一起返回給 client.然後此 連接就 結束事務上下文。

6.1事務命令

<code>#用於標記事物的開始
multi
# 在一個事務中執行所有先前放入隊列的命令, 然後恢復正常的連接狀態
exec
# 清楚所有先前在一個事物中放入隊列的命令, 然後恢復到正常的連接狀態
discard
# 當某個事物需要按條件執行時, 就要使用這個命令給設定的鍵為受監控狀態
watch key [key ...]
# 清除所有先前為一個事物監控的鍵
unwatch/<code>

6.3 事務示例: 銀行轉賬

<code>127.0.0.1:6379> set tom 1000
OK
127.0.0.1:6379> set mike 1000
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby tom 100
QUEUED
127.0.0.1:6379> incrby mike 100
QUEUED
127.0.0.1:6379> exec
1) (integer) 900
2) (integer) 1100
127.0.0.1:6379> mget tom mike
1) "900"
2) "1100"/<code>

6.4 watch

如果在事務執行之前這個(或這些) key 被其他命令所改動,那麼事務將被打斷。

示例: 買票

客戶端一:

<code>127.0.0.1:6379> set ticket 1
OK
127.0.0.1:6379> set ling 1000
OK
127.0.0.1:6379> watch ticket
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decr ticket
QUEUED
127.0.0.1:6379> decrby tom 100
QUEUED/<code>

客戶端二:

<code>127.0.0.1:6379> get ticket
"1"
127.0.0.1:6379> decr ticket
(integer) 0/<code>

客戶端一: 事務被打斷

<code>127.0.0.1:6379> exec
(nil)/<code>

6.5 redis為什麼不支持回滾

在瞭解事務的回滾的時候, 我們先要跳出事務的原子性來看待, redis為了性能的關係, 並不是支持事務的回滾.

我們知道事務的原子性, 就是事務裡面如果全部成功, 要麼全部執行失敗.其實我們這裡要說的, 就是在執行exec的時候, 如果在執行過程中有語法報錯的, 或者中間有失敗的, 那執行過的, 就執行過了, 並不進行回滾操作.

但是discard命令還是可以清楚到以前的所有命令的


分享到:


相關文章: