Redis专题-持久化方式
很多時候我們?yōu)榱司徑鈹?shù)據(jù)庫的壓力,都會使用緩存來作為數(shù)據(jù)的存儲方式,最常用的就是使用redis。將熱點數(shù)據(jù)緩存在redis中可以有效緩解數(shù)據(jù)庫的壓力。但是如果redis掛了那些重要的數(shù)據(jù)怎么辦?redis為我們提供了持久化的機制,它可以保證數(shù)據(jù)不會丟失。接下來我們就來聊聊redis的這一特性。
redis為我們提供了兩種方式的持久化策略:RDB(Redis DataBase)和AOF(Append Only File)。
1.RDB(Redis DataBase)
RDB持久化是將當(dāng)前進程中的數(shù)據(jù)生成快照保存到磁盤(快照持久化),保存的文件后綴為rdb,當(dāng)redis重啟時,可以讀取快照文件恢復(fù)數(shù)據(jù)。
1.1啟用方式
通過在配置文件redis.conf中進行參數(shù)的配置可以開啟或者關(guān)閉是否啟用RDB持久化:
save 900 1 save 300 10 save 60 10000如果將這些注釋掉則可以關(guān)閉RDB持久化。上面每一條的含義如下:
Redis 服務(wù)器在 900 秒之內(nèi),對數(shù)據(jù)庫進行了至少一次修改 Redis 服務(wù)器在 300 秒之內(nèi),對數(shù)據(jù)庫進行了至少 10 次修改 Redis 服務(wù)器在 60 秒之內(nèi),對數(shù)據(jù)庫進行了至少 10000 次修改這種配置的方式為save m n,表示當(dāng)m秒內(nèi)發(fā)生n次變化時,會觸發(fā)bgsave,屬于自動觸發(fā)啟動RDB持久化,我們還可以使用命令save/bgsave來進行手動出發(fā)RDB持久化。save和bgsave雖然都可以觸發(fā)RDB持久化,但是具有不同的特性,這里簡單做一下對比:
| IO類型 | 同步 | 異步 |
| 復(fù)雜度 | O(n) | O(n) |
| 內(nèi)存消耗 | 不會消耗額外內(nèi)存 | 消耗內(nèi)存,需要fork子進程 |
| 是否阻塞 | 阻塞redis服務(wù)器的進程,直到RDB文件創(chuàng)建完,在該期間,redis不能處理任何的命令請求 | 生成RDB文件時,會派生出一個子進程,只有fork子進程期間是阻塞的,子進程負責(zé)創(chuàng)建RDB文件,在此期間,主進程和子進程是同時存在的,不會阻塞redis服務(wù)器進程 |
1.2存儲路徑
打開配置文件redis.conf,則可以看到以下兩個參數(shù):
1.3RDB文件
1.3.1RDB文件格式
Redis的RDB文件是二進制格式的文件,可以用cat命令看一下RDB文件的內(nèi)容:
這里顯示的是一個包含亂碼的文件,因為文件是以二進制的格式保存,要想看到正常的信息,可以通過linux的od命令查看,od命令用于輸出文件的八進制、十六進制或其他格式編碼的字節(jié),通常用于輸出文件中不能直接顯示在終端的字符,注意輸出的是字節(jié),分隔符之間的字符都是保存在一個字節(jié)的。這里就不做演示了,大家想看可以自行進行操作。
1.3.2RDB文件結(jié)構(gòu)
如下圖所示,這里是RDB文件的一個大致結(jié)構(gòu)圖:
為了更好的理解,這里對各個參數(shù)做一下解釋:
注意:只有當(dāng)數(shù)據(jù)庫中有鍵值對時,RDB文件中才會有該數(shù)據(jù)庫的信息,如果Redis中所有的數(shù)據(jù)庫都沒有鍵值對,則這一部分直接省略。
1.3.3RDB文件存儲過程
RDB持久化觸發(fā)的方式包括手動和自動,因為save指令會阻塞服務(wù)進程,所以通常不會使用,自動觸發(fā)雖然指令是save m n,但是最后也是調(diào)用的bgsave,了解了bgsave的原理也就了解了RDB文件存儲的過程,以下是bgsave的執(zhí)行流程圖:
文字描述過程如下:
第二步中bgsave/bgrewriteaof 的子進程不能同時執(zhí)行,主要是基于性能方面的考慮:兩個并發(fā)的子進程同時執(zhí)行大量的磁盤寫操作,可能引起嚴重的性能問題。
1.4 常用配置
這里給大家介紹幾個RDB常用的配置,這些都可以再redis.conf配置文件中進行配置:
//bgsave自動觸發(fā)的條件,沒有save m n配置,相當(dāng)于自動的RDB持久化關(guān)閉,仍可以通過其他方式觸發(fā) save m n //bgsave出現(xiàn)錯誤時,Redis是否停止執(zhí)行寫命令,設(shè)置為yes,則當(dāng)硬盤出現(xiàn)問題時,可以及時發(fā)現(xiàn),避免數(shù)據(jù)的大量丟失 stop-writes-on-bgsave-error yes //是否開啟RDB文件壓縮 rdbcompression yes //是否開啟RDB文件的校驗,在寫入文件和讀取文件時都起作用; rdbchecksum yes //RDB文件名 dbfilename dump.rdb //RDB文件和AOF文件所在目錄 dir ./2.AOF(Append Only File)
RDB持久化是將進程數(shù)據(jù)寫入文件,而AOF持久化(即Append Only File持久化),則是將Redis執(zhí)行的每次寫命令記錄到單獨的日志文件中(有點像MySQL的binlog),與RDB相比,AOF的實時性更好,因此已成為主流的持久化方案。
2.1啟用方式
Redis服務(wù)器默認開啟RDB,關(guān)閉AOF;要開啟AOF,只需要在配置文件中配置:
//開啟AOF appenonly yes2.2存儲路徑
//存儲路徑 dir ./ //存儲文件名,自己定義 appendfilename "appendonly.aof"2.3AOF文件存儲
2.3.1 執(zhí)行流程
AOF的執(zhí)行流程圖大致如下:
2.3.1.1 命令追加(append)
AOF命令追加的內(nèi)容直接是文本協(xié)議格式,那么什么會采用文本協(xié)議格式呢?原因如下:
從流程圖可以看到,追加的內(nèi)容會追加到aof緩沖區(qū)而不是直接寫入aof文件,這樣做的目的是什么呢?
2.3.1.2 文件同步(sync)
在命令追加中提到 Reids可以提供多種緩沖區(qū)同步硬盤的策略,其主要由appendfsync控制,redis提供了三種方式,不同的值具有的特點如下:
| always | 命令寫入aof_buf后立即調(diào)用系統(tǒng)fsync操作同步到AOF文件,fsync完成后線程返回;每次有寫命令都要同步到AOF文件,硬盤IO成為性能瓶頸,Redis只能支持大約幾百TPS寫入,嚴重降低了Redis的性能;即便是使用固態(tài)硬盤(SSD),每秒大約也只能處理幾萬個命令,而且會大大降低SSD的壽命。 |
| everysec | 命令寫入aof_buf后調(diào)用系統(tǒng)write操作,write完成后線程返回。fsync同步文件操作由專門線程每秒調(diào)用一次 |
| no | 命令寫入aof_buf后調(diào)用系統(tǒng)write操作,不對AOF文件做fsync同步,同步硬盤操作由操作系統(tǒng)負責(zé),通常同步周期最長30秒。 |
2.3.1.3 文件重寫(rewrite)
隨著時間流逝,Redis服務(wù)器執(zhí)行的寫命令越來越多,AOF文件也會越來越大;過大的AOF文件不僅會影響服務(wù)器的正常運行,也會導(dǎo)致數(shù)據(jù)恢復(fù)需要的時間過長,所以需要對文件進行重寫。通過多aof文件重寫,減小AOF文件的體積,減少文件占用的空間,加快恢復(fù)速度。需要注意的是AOF重寫是把Redis進程內(nèi)的數(shù)據(jù)轉(zhuǎn)化為寫命令,同步到新的AOF文件,不會對舊的AOF文件進行任何讀取、寫入操作。文件重寫主要做了以下幾個優(yōu)化:
AOF重寫過程依然可以分為手動觸發(fā)和自動觸發(fā)。手動觸發(fā)直接調(diào)用bgrewriteaof命令就可以,自動觸發(fā)根據(jù)auto-aof-rewrite-min-size和auto-aof-rewrite-percentage參數(shù)確定自動觸發(fā)時機:
auto-aof-rewrite-min-size:表示運行AOF重寫時文件最小體積,默認為64MB; auto-aof-rewrite-percentage:代表當(dāng)前AOF文件空間(aof_current_size)和上一次重寫后AOF文件空間(aof_base_size)的比值。自動觸發(fā)時機 = aof_current_size > auto-aof-rewrite-min-size && (aof_current_size - aof_base_size) / aof_base_size >= auto-aof-rewrite=percentage以下是文件重寫的流程圖:
接下來描述一下執(zhí)行過程:
2.3.1.4 重啟加載(load)
關(guān)于redis重啟加載的時候,在這里說明一下假如RDB和AOF都開啟的時候,優(yōu)先加載的是AOF,因為AOF保存的數(shù)據(jù)更加完整,最多只會損失1s的數(shù)據(jù)。我們來看一下redis的源碼:
因為redis的源碼是用c語言寫的,為了提高可讀性,我加了部分中文注釋。通過源碼的解讀我大致畫出了對應(yīng)的流程圖如下:
2.4 常用配置
//是否開啟AOF appendonly no //AOF文件名 appendfilename "appendonly.aof" //RDB文件和AOF文件所在目錄 dir ./ //fsync持久化策略 appendfsync everysec //AOF重寫期間是否禁止fsync no-appendfsync-on-rewrite no //文件重寫觸發(fā)條件之一 auto-aof-rewrite-percentage 100 //文件重寫觸發(fā)條件之一 auto-aof-rewrite-min-size 64mb //如果AOF文件結(jié)尾損壞,Redis啟動時是否仍載入AOF文件 aof-load-truncated yes3.RDB與AOF比較
| AOF | 支持秒級持久化,兼容性好 | 文件大,恢復(fù)速度慢,對性能影響大,官方文檔也指出,在某些情況下,AOF的確也存在一些bug,比如使用阻塞命令時 |
| RDB | RDB文件緊湊,體積小,網(wǎng)絡(luò)傳輸快,適合全量復(fù)制;恢復(fù)速度比AOF快很多;對性能的影響相對較小 | 做不到實時持久化;RDB文件需要滿足特定格式,兼容性差,如老版本的Redis不兼容新版本的RDB文件 |
4.性能與實踐
通過以上的分析可以知道不管是AOF還是RDB都是需要fork出子進程進行操作,這是一個重量級的操作,會對redis造成阻塞,所以為了不影響redis的性能,我們應(yīng)該盡可能的降低阻塞,主要有以下策略可以采用:
- 降低fork頻率,比如關(guān)閉自動,改成手動來進行RDB的快照生成和AOF的重寫;
- 控制redis最大使用內(nèi)存,防止fork耗時過長;
- 采用更高級的硬件設(shè)備;
- 合理配置Linux的內(nèi)存分配策略,避免因物理內(nèi)存不足導(dǎo)致fork失敗。
以上描述的可能太抽象,在實際生產(chǎn)中我們應(yīng)該怎么呢?在這里提供一點自己的實踐經(jīng)驗:
- 如果Redis中的數(shù)據(jù)完全丟棄也沒有關(guān)系(如Redis完全用作DB層數(shù)據(jù)的cache),那么無論是單機,還是主從架構(gòu),都可以不進行任何持久化;
- 單機如果出現(xiàn)多個實例,要防止多個及其同時運行持久化和重寫操作,避免出現(xiàn)內(nèi)存,CPU,IO資源競爭,讓持久化變?yōu)榇?#xff1b;
- 在單機環(huán)境下(對于個人開發(fā)者,這種情況可能比較常見),如果可以接受十幾分鐘或更多的數(shù)據(jù)丟失,選擇RDB對Redis的性能更加有利;如果只能接受秒級別的數(shù)據(jù)丟失,應(yīng)該選擇AOF;
- 在多數(shù)情況下,我們都會配置主從環(huán)境,slave的存在既可以實現(xiàn)數(shù)據(jù)的熱備,也可以進行讀寫分離分擔(dān)Redis讀請求,以及在master宕掉后繼續(xù)提供服務(wù)。在這種情況下的可行做法是master完全關(guān)閉持久化(包括RDB和AOF),這樣可以讓master的性能達到最好。
- RDB和AOF可以同時存在,配合使用提高效率。
猜你感興趣:
Redis專題-集群模式
Redis專題-持久化方式
Redis專題-底層數(shù)據(jù)結(jié)構(gòu)與使用場景
Redis專題-緩存穿透、緩存雪崩、緩存擊穿
更多文章請點擊:更多…
總結(jié)
以上是生活随笔為你收集整理的Redis专题-持久化方式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Redis专题-底层数据结构与使用场景
- 下一篇: Redis专题-集群模式