6. 持久化(RDB/AOF)
? 眾所周知排苍,Redis是個將數(shù)據(jù)存在內(nèi)存的數(shù)據(jù)庫墩崩,當機器宕機的時候數(shù)據(jù)會全部丟失心赶。因此Redis給了兩種持久化方案,即:RDB(Redis DataBase)和 AOF(Append Only File)鲁冯。
? 講點題外話拷沸,相信接觸過Redis的同學或多或少對于Redis的持久化方案有所了解。但是持久化并不是Redis的專屬薯演,也不是內(nèi)存型數(shù)據(jù)的專屬撞芍。當我們的數(shù)據(jù)需要備份的時候其實都需要持久化方案(可能不叫”持久化“而是叫”備份“),例如:雙機熱備涣仿、主從備份勤庐、跨機房備份等等。其實所謂持久化就是一份數(shù)據(jù)在發(fā)生意外情況時能夠有另一份備份數(shù)據(jù)來繼續(xù)支持外部使用好港。當然在整個過程中必然會出現(xiàn)源數(shù)據(jù)和備份數(shù)據(jù)不一致的情況愉镰。無需去糾結(jié)如何才能做到數(shù)據(jù)完全一致,而是要考慮真實的需求和技術(shù)之間的結(jié)合钧汹。
6.1 RDB
? RDB持久化其實就是快照丈探。顧名思義,就像我們拍照時拔莱,照片會記錄我們某一瞬間的圖像碗降;而快照會記錄我們某一瞬間的數(shù)據(jù)。
6.1.1 SAVE & BGSAVE
? Redis可以使用SAVE命令和BGSAVE命令來將內(nèi)存中的數(shù)據(jù)刷到磁盤中塘秦。
? 當執(zhí)行SAVE命令時讼渊,Redis服務(wù)器會被阻塞,由于Redis是單工作線程模型的尊剔,這時客戶端發(fā)送的所有命令都會被阻塞爪幻。所以一般情況我們不會執(zhí)行SAVE命令。
? BGSAVE就很好的規(guī)避了SAVE阻塞線程的情況须误,因為當調(diào)用BGSAVE的時候Redis會調(diào)用glibc的函數(shù)fork產(chǎn)生一個子進程挨稿,然后由這個子進程來實現(xiàn)快照持久化。這里會使用Linux操作系統(tǒng)的cow機制(在<1.4.4 Rehash>中提到過cow機制)來節(jié)省內(nèi)存資源京痢。
6.1.2 RDB對過期健的處理
? 由于Redis采用了惰性刪除奶甘,所以內(nèi)存中可能存在一些過期了但未被刪除的數(shù)據(jù),當執(zhí)行SAVE或BGSAVE的時候程序會對數(shù)據(jù)庫里的key進行檢查祭椰,如果key已過期則不會保存到新創(chuàng)建的RDB文件中臭家。
6.1.3 RDB文件載入數(shù)據(jù)庫
? 在啟動Redis服務(wù)器時,如果服務(wù)器開啟了RDB功能方淤,那么服務(wù)器將對RDB文件進行載入侣监,載入期間服務(wù)器會一直處于阻塞狀態(tài),當載入完成后服務(wù)器才能對外提供服務(wù)臣淤。
注意:
如果同時開啟了RDB和AOF橄霉,那么只會載入AOF,并不會載入RDB。
如果服務(wù)器以主服務(wù)器模式運行姓蜂,RDB文件中的過期鍵會被丟棄按厘。
如果服務(wù)器以從服務(wù)器模式運行,RDB文件中的過期健仍然會被加載到
6.1.4 RDB配置
redis.conf文件中saveparams的默認配置:
save 900 1
save 300 10
save 60 10000
具體的含義是钱慢,有以下三個條件之一逮京,BGSAVE就會被執(zhí)行:
在900秒之內(nèi),對數(shù)據(jù)庫進行了至少1次修改
在300秒之內(nèi)束莫,對數(shù)據(jù)庫進行了至少10次修改
在60秒之內(nèi)懒棉,對數(shù)據(jù)庫進行了至少10000次修改
redisServer結(jié)構(gòu)體中會保存dirty(修改計數(shù)器)和lastsave(上一次執(zhí)行保存的時間)來實現(xiàn)具體的判斷。
6.2 AOF
? AOF持久化其實就是命令執(zhí)行日志览绿。它是連續(xù)增量的策严,內(nèi)部具體內(nèi)容滿足Redis通信協(xié)議。(具體RESP可在<3.3 redis的通信協(xié)議>中查看)
6.2.1 AOF原理
AOF持久化功能的實現(xiàn)大致分為命令追加饿敲、文件寫入妻导、文件同步三個步驟。
命令追加:當Redis服務(wù)器執(zhí)行完一個命令之后怀各,會以RESP格式追加到aof_buf緩沖區(qū)的末尾
文件寫入:服務(wù)器每次結(jié)束一個事件循環(huán)之前倔韭,都會調(diào)用flushAppendOnlyFile來將aof_buf中的內(nèi)容寫到AOF文件。
文件同步:將寫入AOF緩沖區(qū)的數(shù)據(jù)同步到磁盤上瓢对。
寫入(write)和同步(fsync)其實是操作系統(tǒng)為了提高效率設(shè)置的一個機制寿酌,當調(diào)用write的時候,系統(tǒng)會將數(shù)據(jù)暫時保存在內(nèi)存緩沖區(qū)硕蛹,當緩沖區(qū)空間被填滿或者超過了指定的時間醇疼,數(shù)據(jù)才會被真正寫到磁盤上。這樣的機制雖然提高了寫入效率但帶來了宕機數(shù)據(jù)丟失的風險妓美,為此系統(tǒng)提供了fsync和fdatasync兩個同步函數(shù),可以讓緩沖區(qū)的數(shù)據(jù)立即寫到磁盤中鲤孵。
小提示:在Redis4.0之后AOF Sync的操作被移到一個獨立異步的線程去做壶栋,防止阻塞主線程。
配置文件中有對fsync各級別的詳細說明(默認超1秒同步一次):
# The fsync() call tells the Operating System to actually write data on disk
# instead of waiting for more data in the output buffer. Some OS will really flush
# data on disk, some other OS will just try to do it ASAP.
#
# Redis supports three different modes:
#
# no: don't fsync, just let the OS flush the data when it wants. Faster.
# always: fsync after every write to the append only log. Slow, Safest.
# everysec: fsync only one time every second. Compromise.
#
# The default is "everysec", as that's usually the right compromise between
# speed and data safety. It's up to you to understand if you can relax this to
# "no" that will let the operating system flush the output buffer when
# it wants, for better performances (but if you can live with the idea of
# some data loss consider the default persistence mode that's snapshotting),
# or on the contrary, use "always" that's very slow but a bit safer than
# everysec.
#
# More details please check the following article:
# http://antirez.com/post/redis-persistence-demystified.html
#
# If unsure, use "everysec".
# appendfsync always
appendfsync everysec
# appendfsync no
6.2.2 AOF重寫
? 隨著Redis對外提供服務(wù)的時間增長普监,必然會導致AOF文件越來越大贵试,不論是對于宿主機器的磁盤資源還是AOF重放來說,都不是一件好事凯正。所以為了保證資源合理使用毙玻、服務(wù)正常運行,AOF有一個重寫功能廊散,重寫完之后的AOF不會浪費空間桑滩,保證數(shù)據(jù)完整性的前提下使得新AOF文件體積小于原AOF文件。
整個AOF重寫和原AOF文件半毛錢關(guān)系沒有允睹,簡單來說就分了三步:
- 新建一個AOF文件重寫文件运准。
- 保存一份當前Redis數(shù)據(jù)庫的快照放在重寫文件頭部幌氮。
- 將新產(chǎn)生的日志append到重寫文件中,替換原AOF文件胁澳。
6.2.3 AOF重寫觸發(fā)機制
Redis觸發(fā)AOF重寫的機制有三種:
Redis服務(wù)器接收到客戶端發(fā)送的BGREWRITEAOF指令請求该互,如果當前AOF/RDB數(shù)據(jù)持久化沒有在執(zhí)行,那么就執(zhí)行BGREWRITEAOF命令韭畸,否則Redis會等當前AOF/RDB數(shù)據(jù)持久化結(jié)束后再執(zhí)行宇智。
用戶設(shè)置”config set appendonly yes“開啟AOF的時,調(diào)用startAppendOnly函數(shù)會觸發(fā)AOF重寫胰丁。
在Redis配置文件redis.conf中随橘,用戶設(shè)置了auto-aof-rewrite-percentage(默認100)和auto-aof-rewrite-min-size(默認64mb)參數(shù),并且當前AOF文件大小server.aof_current_size大于auto-aof-rewrite-min-size(server.aof_rewrite_min_size)隘马,同時AOF文件大小的增長率大于auto-aof-rewrite-percentage(server.aof_rewrite_perc)時太防,會自動觸發(fā)AOF重寫。
以下為配置文件中的說明:
# Automatic rewrite of the append only file.
# Redis is able to automatically rewrite the log file implicitly calling
# BGREWRITEAOF when the AOF log size grows by the specified percentage.
#
# This is how it works: Redis remembers the size of the AOF file after the
# latest rewrite (if no rewrite has happened since the restart, the size of
# the AOF at startup is used).
#
# This base size is compared to the current size. If the current size is
# bigger than the specified percentage, the rewrite is triggered. Also
# you need to specify a minimal size for the AOF file to be rewritten, this
# is useful to avoid rewriting the AOF file even if the percentage increase
# is reached but it is still pretty small.
#
# Specify a percentage of zero in order to disable the automatic AOF
# rewrite feature.
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb