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命令還是可以清楚到以前的所有命令的
閱讀更多 故事凌 的文章