今天就跟大家聊聊有關(guān)redis中持久化RDB和AOF的原理是什么,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
為德州等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計(jì)制作服務(wù),及德州網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)、德州網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!
RDB基礎(chǔ)知識
RDB文件存在是以一個(gè)壓縮后的二進(jìn)制文件,這個(gè)RDB文件一般是保存在Redis安裝目錄下,通過啟動(dòng)Redis服務(wù)器執(zhí)行rdbLoad函數(shù)加載RDB文件,執(zhí)行rdbSave函數(shù)保存RDB文件。
RDB保存
rdbSave函數(shù)負(fù)責(zé)將內(nèi)存中的數(shù)據(jù)庫數(shù)據(jù)以RDB格式保存到磁盤中,如果RDB文件已存在,那么新的RDB文件將替換已有的RDB文件,SAVE和BGSAVE兩個(gè)命令都會(huì)調(diào)用rdbSave函數(shù)。
SAVE直接調(diào)用rdbSave,阻塞Redis主進(jìn)程,直到保存完成為止。在主進(jìn)程阻塞期間,服務(wù)器不能處理客戶端的任何請求。
BGSAVE則開啟一個(gè)子進(jìn)程,子進(jìn)程負(fù)責(zé)調(diào)用rdbSave,Redis服務(wù)器在BGSAVE執(zhí)行期間仍然可以繼續(xù)處理客戶端的請求,并在保存完成之后向主進(jìn)程發(fā)送信號,通知保存已完成。
注意:執(zhí)行保存命令時(shí)Redis不會(huì)再次執(zhí)行save、bgsave、bgrewriteaof等命令,因?yàn)槿绻麍?zhí)行這些命令會(huì)存在資源搶占使備份出現(xiàn)意想不到的bug。
自動(dòng)隔離保存
此時(shí)我們的小伙伴意識到,我們不能每次都執(zhí)行命令手動(dòng)保存或者執(zhí)行定時(shí)器執(zhí)行命令,這樣會(huì)導(dǎo)致可用性降低,那么Redis提供自動(dòng)保存的配置
####100秒內(nèi)對Redis進(jìn)行10次以上的修改save 100 10####一小時(shí)內(nèi)對Redis進(jìn)行至少1000次的修改save 3600 1000###只要滿足上面任何一個(gè)要求則執(zhí)行bgsave命令
那么Redis源代碼中保存這個(gè)配置的是在redisServer中的一個(gè)saveparam的結(jié)構(gòu),代碼如下:
struct saveparam { teme_t seconds; //秒 int changes; //修改數(shù)}
save我們這里就不分析了,因?yàn)樗苯幼枞骶€程把Redis數(shù)據(jù)直接寫入磁盤文件,所以我們這對bgsave進(jìn)行講解,前面說了bgsave是開啟一個(gè)子進(jìn)程進(jìn)行文件的操作,那么此時(shí)的Redis主進(jìn)程還在響應(yīng)客戶端的命令,那么我們的Redis如何保證數(shù)據(jù)完整性和性能呢?
Redis在持久化的時(shí)候會(huì)fork產(chǎn)生一個(gè)子進(jìn)程,持久化過程完全交給子進(jìn)程,而父進(jìn)程則響應(yīng)客戶端的命令,子進(jìn)程創(chuàng)建時(shí)不會(huì)立即保存文件因?yàn)檫@會(huì)與父進(jìn)程產(chǎn)生資源搶占,它的指針指向父進(jìn)程的內(nèi)存空間與父進(jìn)程共享內(nèi)存,這樣為了更加節(jié)約資源。
此時(shí)父進(jìn)程是會(huì)讀寫內(nèi)存中的數(shù)據(jù),子進(jìn)程只是讀取資源并不會(huì)寫,此時(shí)Redis使用操作系統(tǒng)的多進(jìn)程COW(Copy On Write)機(jī)制進(jìn)行數(shù)據(jù)段頁面的分離,每頁數(shù)據(jù)不會(huì)超過4K,我們把這個(gè)數(shù)據(jù)稱之為冷數(shù)據(jù),父進(jìn)程進(jìn)行修改的時(shí)候我們只需要把共享的頁數(shù)據(jù)復(fù)制出來對其進(jìn)行修改,而不在原數(shù)據(jù)上進(jìn)行修改,冷數(shù)據(jù)沒有任何的變化。子進(jìn)程現(xiàn)在可以安心的對冷數(shù)據(jù)進(jìn)行持久化,此時(shí)我們持久化的內(nèi)容就像是被拍了照一樣固定下來,這就是快照的整個(gè)過程。
這里值得注意的是隨著時(shí)間的推移,父進(jìn)程修改的頁也會(huì)越來越多,理論上這個(gè)復(fù)制出來的內(nèi)存能達(dá)到之前數(shù)據(jù)內(nèi)存,所以我們在設(shè)計(jì)緩存的時(shí)候盡可能的少改數(shù)據(jù)。
Redis還有一個(gè)持久化操作那就是AOF(Append Only File),AOF是將客戶端的修改指令保存下來追加到服務(wù)器狀態(tài)的aof_buf緩沖區(qū)尾部,最后保存到AOF日志文件。舉個(gè)例子。
首先,前面我們講過Redis的通訊協(xié)議RESP,我們這里把客戶端的指令轉(zhuǎn)換成這種協(xié)議
>set name mango####保存到aof_buf緩沖區(qū)*3\r\n$3\r\nset\r\n$4\r\name\r\n$5\r\mango\r\n
然后我們將協(xié)議文本追加到aof_buf末尾
最后我們把這些指令信息保存至AOF日志文件中
AOF保存模式
每當(dāng)服務(wù)器常規(guī)任務(wù)函數(shù)被執(zhí)行、或者事件處理器被執(zhí)行時(shí),aof.c/flushAppendOnlyFile函數(shù)都會(huì)被調(diào)用,這個(gè)函數(shù)執(zhí)行以下兩個(gè)工作:
WRITE:根據(jù)條件,將aof_buf中的緩存寫入到AOF文件。
SAVE:根據(jù)條件,調(diào)用fsync或fdatasync函數(shù),將AOF文件保存到磁盤中。
Redis目前支持三種AOF保存模式:
1. AOF_FSYNC_NO:不保存,操作系統(tǒng)來決定什么時(shí)候保存保存。
2. AOF_FSYNC_EVERYSEC:每一秒鐘保存一次。
3. AOF_FSYNC_ALWAYS:總是保存,每執(zhí)行一個(gè)命令保存一次。
這三種模式從上到下執(zhí)行速度越來越慢,安全性越來越高,如果使用no模式,那么恢復(fù)數(shù)據(jù)會(huì)恢復(fù)到上次備份,如果是everysec最多會(huì)丟失一秒,而always只會(huì)丟失一個(gè)指令。所以我們考慮使用哪種AOF模式取決于我們的業(yè)務(wù)需求綜合考慮。
關(guān)于fsync
AOF日志是以文件的形式存在的,當(dāng)我們的AOF從緩沖區(qū)寫入AOF文件中時(shí)服務(wù)器突然宕機(jī),此時(shí)我們的文件還沒有完全寫入磁盤,這時(shí)我們該如何處理呢?
fsync函數(shù)可以將指定文件的內(nèi)容強(qiáng)制從內(nèi)核緩存刷到磁盤。只要Redis進(jìn)程實(shí)時(shí)調(diào)用fsync函數(shù)就可以保證AOF日志不失。但是fsync是一個(gè)磁盤IO操作,so它很慢。如果Redis執(zhí)行一條指令就要fsync一次,那么可想而知Redis的性能就會(huì)拉下一大截 。
所以在生產(chǎn)環(huán)境的服務(wù)器中,Redis通常是每隔1s左右執(zhí)行一次fsync操作,這個(gè)1s的周期是可以配置的。這是在數(shù)據(jù)安全性和性能之間做的一個(gè)折中,在保持高性能的同時(shí),盡可能使數(shù)據(jù)少丟失。
Redis同樣也提供了另外兩種策略,一個(gè)是永不調(diào)用fsync讓操作系統(tǒng)來決定何時(shí)同步碰盤,這樣做很不安全,另一個(gè)是來一個(gè)指令就調(diào)用fsync一次——結(jié)果導(dǎo)致非常慢。這兩種策略在生產(chǎn)環(huán)境中基本不會(huì)使用。
AOF重寫
我們的AOF一直累加進(jìn)行持久化,隨著時(shí)間的推移備份文件會(huì)越來越大,甚至影響我們對Redis的恢復(fù)和操作,Redis也提供重寫機(jī)制,下面我們來看看
>set name zhangsan>set name mango>set name lisi...>set name mango####優(yōu)化后>set name mango
我們可以看到經(jīng)常會(huì)對一個(gè)key進(jìn)行多次修改,那么我們可以把這個(gè)key的最后一次操作保存起來這樣我們就輕易的給AOF"瘦身"。當(dāng)然我們還有一種方式,就是遍歷整個(gè)Redis,set每個(gè)key和它的值,也跟RDB全備一樣我們需要一個(gè)子進(jìn)程讀取當(dāng)前的Redis庫。
這里會(huì)出現(xiàn)一個(gè)問題,我們?nèi)绻潜闅v整個(gè)Redis需要考慮此時(shí)的客戶端必定會(huì)有指令更改里面的值,此時(shí)我們怎么保證AOF重寫后不丟下重寫后的指令呢?
操作步驟:
AOF創(chuàng)建一個(gè)子進(jìn)程進(jìn)行AOF重寫,其指定內(nèi)存跟主進(jìn)程一致
客戶端執(zhí)行寫命令,主線程處理指令,指令追加到AOF緩沖區(qū),并且追加到AOF重寫緩沖區(qū)
AOF重寫完成后替換現(xiàn)有的AOF文件
那么為什么會(huì)把這個(gè)指令同時(shí)追加到AOF緩沖區(qū)和AOF重寫區(qū)呢?原因是如果我們在重寫的時(shí)候突然服務(wù)器掛了,那么我們AOF文件中會(huì)保存這個(gè)指令。追加到AOF緩沖區(qū)是為了保證操作指令能及時(shí)同步到AOF重寫區(qū)。AOF重寫操作也就是之前提到過的bgrewriteaof。
Redis4.0為了解決這個(gè)問題,帶來了一個(gè)新的持久化選項(xiàng)一一混合持久化。將RDB文件的內(nèi)容和增量的AOF日志文件存在一起。這里的AOF日志不再是全量的曰志,而是自持久化開始到持久化結(jié)束的這段時(shí)間發(fā)生的增量AOF日志,通常這部分AOF日志很小。
在Redis重啟的時(shí)候,可以先加載RDB,然后再重放增量AOF日志,就可以完全替代之前的AOF全量文件重放,重啟效率因此得到大幅提升。
總結(jié)一下:
Redis持續(xù)化操作包括RDB和AOF
RDB保存的是一個(gè)壓縮二進(jìn)制文件,AOF保存的是操作指令文件
Redis優(yōu)先恢復(fù)AOF,因?yàn)樗容^全,Redis4.0采用混合模式來恢復(fù)
RDB執(zhí)行bgsave時(shí)和AOF重寫一樣,開啟一個(gè)子進(jìn)程,他們的內(nèi)存與父進(jìn)程共享
AOF有三種保存模式,no不主動(dòng)保存依賴操作系統(tǒng)調(diào)度;everysec一秒執(zhí)行一次;always每次執(zhí)行一個(gè)指令保存一次。
AOF保存模式主要是fsync函數(shù),保證AOF日志不會(huì)丟失
看完上述內(nèi)容,你們對Redis中持久化RDB和AOF的原理是什么有進(jìn)一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。