本章節(jié)我們來看看Redis時如何就愛那個數(shù)據(jù)存儲到硬盤里面,是的數(shù)據(jù)在Redis重啟之后仍然存在的。Redis提供了兩種不同的持久化方法來將數(shù)據(jù)存儲到硬盤里面。一種方法叫快照(snapshotting),它可以將存在于某一時刻的所有數(shù)據(jù)都寫入硬盤里;另一種方法教只追加文件(append-only file, AOF),它會在執(zhí)行的寫命令復(fù)制到硬盤里。這兩種方法可以自由搭配使用,具體如何選擇,需要根據(jù)用書的數(shù)據(jù)以及應(yīng)用來決定。下面在Redis安裝目錄的redis.conf文件中查看下Redis默認(rèn)的持久化配置:
|
|
可以看出默認(rèn)開啟的時快照模式,AOF模式是關(guān)閉的,具體的配置項是什么意思后面再看,這里先了解下哪里可以修改配置以及Redis默認(rèn)行為。
快照持久化
用戶可以將快照復(fù)制到其他服務(wù)器已達(dá)到備份的效果,也可以就將快照留在原地以便重啟服務(wù)器時使用,快照文件存在dbfilename選項指定的文件中,并存儲在dir指定的路徑,根據(jù)默認(rèn)配置即./dump.rdb,如果在新的快照文件創(chuàng)建之前,Redis、操作系統(tǒng)或者硬件三者任意一個崩潰了,Redis會丟失最近一次創(chuàng)建快照之后寫入的所有數(shù)據(jù)。創(chuàng)建快照有以下幾種方式:
- 客戶端主動發(fā)送BGSAVE命令來創(chuàng)建一個快照,BGSAVE命令返回Background saving started,Redis是通過調(diào)用fork來創(chuàng)建子進(jìn)程完成快照寫入硬盤的,父進(jìn)程可以繼續(xù)響應(yīng)命令請求。
- 客戶端主動發(fā)送SAVE命令來創(chuàng)建一個快照,接到SAVE命令的Redis服務(wù)器在快照創(chuàng)建完畢之前將不再響應(yīng)任何其他請求,此命令不常用。
- 配置save選項,例如save 60 10000,那么從Redis最近一次創(chuàng)建快照之后開始算起,當(dāng)”60秒之內(nèi)有10000次寫入”這個條件被滿足時,Redis就會自動出發(fā)BGSAVE命令,如果設(shè)置了多個save配置選項,當(dāng)任意一個滿足時,Redis就會出發(fā)BGSAVE。默認(rèn)行為配置了三個闕值。
- 當(dāng)Redis通過SHUTDOWN命令接受到關(guān)閉服務(wù)器的請求時,或者接受到標(biāo)準(zhǔn)TERM信號時,會執(zhí)行一個SAVE命令,阻塞所有客戶端,并在SAVE命令執(zhí)行完畢之后關(guān)閉服務(wù)器。
- 當(dāng)一個Redis服務(wù)器連接另一個Redis服務(wù)器,并向?qū)Ψ桨l(fā)送SYNC命令開始一次復(fù)制操作的時候,如果主服務(wù)器沒有或者并非剛剛執(zhí)行BGSAVE操作,那么主服務(wù)器就會執(zhí)行BGSAVE命令。
由于快照持久化會會在系統(tǒng)發(fā)生崩潰時丟失數(shù)據(jù),因此只適用于那些即使丟失一部分?jǐn)?shù)據(jù)葉不會造成問題的應(yīng)用程序,如果不能接受這樣的損失,可以參考后面AOF持久化。下面列舉一些使用于快照持久化的場景:
1. 個人開發(fā)
個人開發(fā)服務(wù)器上,考慮到降低快照持久化帶來的資源消耗,可以只設(shè)置sava 900 1,意思是距離上一次成功生成快照已經(jīng)超過900秒,并且在此期間至少執(zhí)行了一次寫入操作,Redis就會自動開始一次新的BGSAVE操作。
2. 對日志進(jìn)行聚合計算
在處理日志的同時,記錄被處理日志的文件以及偏移量,如果Redis奔潰了而未能生成新的快照,可以從最后一次生成快照開始重新處理日志文件即可。
3. 大數(shù)據(jù)
當(dāng)Redis存儲數(shù)據(jù)量只有幾個GB的時候,使用快照來保存數(shù)據(jù)是沒有問題的,生成快照的時間葉非常短。但隨著Redis占用的內(nèi)存越來越多時,BGSAVE在創(chuàng)建子進(jìn)程時耗費的時間也越來越多,所以選擇合適的創(chuàng)建快照方式以及妥善地處理可能出現(xiàn)的數(shù)據(jù)丟失,對快照持久化數(shù)據(jù)來說相當(dāng)重要。
AOF持久化
簡單來說,AOF持久化會將被執(zhí)行的寫命令寫到AOF文件的末尾,以此來記錄數(shù)據(jù)的變化。因此,Redis只要從頭到位重新執(zhí)行一次AOF文件包含的所有命令,就可以恢復(fù)AOF文件所記錄的數(shù)據(jù)集。下面列舉appendfsync配置選項對AOF文件的同步頻率的影響:
命令 | 描述 |
---|---|
always | 每個Reids寫命令都要同步寫入硬盤,這樣做會嚴(yán)重降低Redis的速度 |
everysec | 每秒執(zhí)行一次同步,顯示地將多個寫命令同步到硬盤 |
no | 讓操作系統(tǒng)來決定應(yīng)該何時進(jìn)行同步 |
注:這里稍微解釋下文件同步,在向硬盤寫入文件時,寫入內(nèi)容首先會被存儲到緩沖區(qū),然后由操作系統(tǒng)決定何時將緩沖區(qū)內(nèi)容寫入到硬盤,這樣才算真正的寫入數(shù)據(jù)了。sync操作就是命令操作系統(tǒng)將文件同步到硬盤,同步操作會一直阻塞直到指定的文件被寫入硬盤為止。當(dāng)同步操作執(zhí)行完畢之后,即使系統(tǒng)出現(xiàn)故障,只要硬盤不壞,就不會對被同步的文件造成任何影響。
appendfsync always選項是最安全同時也是最慢的,某些情況下還可能會影響固態(tài)硬盤的使用壽命,所以慎用!為了兼顧數(shù)據(jù)安全和寫入性能,可以考慮使用appendfsync everysec,也是Redis默認(rèn)行為。Redis每秒同步一次AOF文件的性能和不適用任何持久化特性時的性能相差無幾,而每秒一次的同步,當(dāng)系統(tǒng)出現(xiàn)故障時,也最多只會丟失一秒內(nèi)產(chǎn)生的數(shù)據(jù)。appendfsync no選項是將寫入硬盤的決定權(quán)交給操作系統(tǒng),如果硬盤的寫入速度不夠快,緩沖區(qū)被填滿時,Redis的寫入操作將被阻塞,從而導(dǎo)致Redis處理命令請求的速度變慢,所以appendfsync no也不推薦使用。
重寫/壓縮AOF文件
AOF持久化看似很美好,有什么理由不使用呢?實際上并沒那么簡單,因為Redis會不斷地將被執(zhí)行的寫命令記錄到AOF文件中,AOF文件的體積會越來越大,極端情況下可能會撐滿硬盤;另外一個問題是,Redis在重啟之后需要通過重新執(zhí)行AOF文件記錄的所有寫命令來還原數(shù)據(jù)集,所以如果AOF文件的體積非常大,那么還原操作執(zhí)行的時間就可能非常長。
為了解決上述問題,可以向Redis發(fā)送BGREWRITEAOF命令,BGREWRITEAOF命令會通過移除AOF文件中的冗余命令來重寫AOF文件,使得AOF文件的體積變得盡可能的小。也可以設(shè)置auto-aof-rewrite-percentage和auto-aof-rewrite-min-size來自動觸發(fā)BGREWRITEAOF命令。Redis默認(rèn)行為的意思是當(dāng)AOF的體積大于64M,并且比上一次重寫之后的體積大了至少一倍(100%)的時候,Redis將執(zhí)行BGREWRITEAOF命令。如果AOF重寫執(zhí)行的國語頻繁的話,可以調(diào)整auto-aof-rewrite-percentage選項的值設(shè)置為100以上,讓Redis在AOF文件的體積變得更大之后才執(zhí)行重寫操作。