前言:redis是內(nèi)存數(shù)據(jù)庫品嚣,它將自己的數(shù)據(jù)保存在內(nèi)存中,所以如果不想辦法將內(nèi)存中的數(shù)據(jù)保存到磁盤里面癌淮,那么一旦服務(wù)器程序退出竟稳,服務(wù)器中的數(shù)據(jù)就會(huì)消失不見属桦。
為了解決這個(gè)問題,redis提供了RDB持久化功能住练,這個(gè)功能可以將redis內(nèi)存中的數(shù)據(jù)保存到磁盤中地啰。RDB持久化既可以手動(dòng)執(zhí)行,又可以通過服務(wù)器配置來定期執(zhí)行讲逛。RDB文件是一個(gè)經(jīng)過壓縮的二進(jìn)制文件亏吝,通過該文件可以還原生成RDB文件時(shí)的數(shù)據(jù)庫狀態(tài)。
1盏混、RDB文件的創(chuàng)建和載入
? ? 有兩個(gè)redis命令可以生成RDB文件蔚鸥,一個(gè)是SAVE惜论,一個(gè)是BGSAVE。
? ? SAVE命令可以直接阻塞服務(wù)器進(jìn)程止喷,知道RDB文件創(chuàng)建完畢馆类。
? ? BGSAVE則是會(huì)派生出一個(gè)子進(jìn)程,然后由子進(jìn)程負(fù)責(zé)創(chuàng)建RDB文件弹谁,父進(jìn)程繼續(xù)處理命令請(qǐng)求乾巧。
? ? 而RDB文件的載入是在服務(wù)器啟動(dòng)的時(shí)候自動(dòng)執(zhí)行的,所以redis并沒有用于載入RDB文件的命令预愤,只要redis服務(wù)器啟動(dòng)的時(shí)候檢測(cè)到了RDB文件的存在沟于,他就會(huì)自動(dòng)載入RDB文件。
????另外植康, 因?yàn)?AOF 文件的保存頻率通常要高于 RDB 文件保存的頻率旷太, 所以一般來說, AOF 文件中的數(shù)據(jù)會(huì)比 RDB 文件中的數(shù)據(jù)要新销睁。因此供璧, 如果服務(wù)器在啟動(dòng)時(shí), 打開了 AOF 功能冻记, 那么程序優(yōu)先使用 AOF 文件來還原數(shù)據(jù)睡毒。 只有在 AOF 功能未打開的情況下, Redis 才會(huì)使用 RDB 文件來還原數(shù)據(jù)冗栗。
? ? 注意:
? ? BGSAVE過程中吕嘀,如果重新發(fā)送SAVE或者BGSAVE命令會(huì)被服務(wù)器拒絕,因?yàn)橥瑫r(shí)執(zhí)行rdbSAVE可能會(huì)產(chǎn)生竟態(tài)贞瞒。
? ? BGSAVE和BGREWRITEAOF不能同時(shí)執(zhí)行的。如果BGSAVE正在執(zhí)行趁曼,那么客戶端發(fā)送的BGREWRITEAOF會(huì)被延遲到BGSAVE命令執(zhí)行完畢之后執(zhí)行军浆。如果BGREWRITEAOF正在執(zhí)行,那么BGSAVE會(huì)被拒絕挡闰。其實(shí)這兩個(gè)命令在操作方面并沒有什么沖突的大方乒融,都是子進(jìn)程來執(zhí)行,不能同時(shí)執(zhí)行只是出于性能的考慮——兩個(gè)子進(jìn)程同時(shí)大量寫入磁盤總感覺不是一個(gè)好主意摄悯。
2赞季、自動(dòng)間隔性保存
? ? 因?yàn)锽GSAVE命令不阻塞服務(wù)器的主進(jìn)程,所以redis允許用戶在配置文件中通過設(shè)置save選項(xiàng)奢驯,來每隔一段時(shí)間自動(dòng)執(zhí)行一次BGSAVE申钩。
save 900 1
save 300 10
save 60? ?10000
? ?上述條件只需要滿足一個(gè)即執(zhí)行BGSAVE。比如900秒之類瘪阁,對(duì)數(shù)據(jù)庫至少對(duì)了一次修改撒遣。
?2.1邮偎、保存設(shè)置的save條件
struct redisServer {?
? ? struct saveparam *saveparams; // 記錄了保存條件的數(shù)組
? ? long long dirty; // 修改計(jì)數(shù)器
? ? time_t lastsave;// 上一次執(zhí)行保存的時(shí)間
}
struct?saveparam{
????time_t seconds; // 秒數(shù)
? ? int changes; //修改數(shù)?
}
? ? dirty計(jì)數(shù)器記錄距離上一次成功執(zhí)行SAVE或者BGSAVE命令之后义黎,服務(wù)器對(duì)數(shù)據(jù)庫狀態(tài)進(jìn)行了多少次修改禾进。
? ? lastsave屬性是一個(gè)UNIX時(shí)間戳,記錄了服務(wù)器上一次成功執(zhí)行SAVE或BGSAVE命令的時(shí)間廉涕。
2.2泻云、檢查保存條件是否滿足? ??
? ? redis的服務(wù)器周期性操作函數(shù)severCron默認(rèn)是100ms執(zhí)行一次(hz設(shè)置),該函數(shù)其中一項(xiàng)工作就是檢查save選項(xiàng)所設(shè)置的保存條件是否滿足狐蜕,如果滿足宠纯,執(zhí)行BGSAVE指令。
3馏鹤、RDB文件結(jié)構(gòu)
?REDIS:
文件的最開頭保存著?REDIS?五個(gè)字符征椒,標(biāo)識(shí)著一個(gè) RDB 文件的開始。在讀入文件的時(shí)候湃累,程序可以通過檢查一個(gè)文件的前五個(gè)字節(jié)勃救,來快速地判斷該文件是否有可能是 RDB 文件。
RDB-VERSION:
一個(gè)四字節(jié)長(zhǎng)的以字符表示的整數(shù)治力,記錄了該文件所使用的 RDB 版本號(hào)蒙秒。因?yàn)椴煌姹镜?RDB 文件互不兼容,所以在讀入程序時(shí)宵统,需要根據(jù)版本來選擇不同的讀入方式晕讲。
EOF :
常量,長(zhǎng)度為?1?字節(jié)马澈, 這個(gè)常量標(biāo)志著 RDB 文件正文內(nèi)容的結(jié)束瓢省, 當(dāng)讀入程序遇到這個(gè)值的時(shí)候, 它知道所有數(shù)據(jù)庫的所有鍵值對(duì)都已經(jīng)載入完畢了痊班。
check_sum :
是一個(gè)?8?字節(jié)長(zhǎng)的無符號(hào)整數(shù)勤婚, 保存著一個(gè)校驗(yàn)和, 這個(gè)校驗(yàn)和是程序通過對(duì)?REDIS?涤伐、?db_version?馒胆、?databases?、?EOF?四個(gè)部分的內(nèi)容進(jìn)行計(jì)算得出的凝果。 服務(wù)器在載入 RDB 文件時(shí)祝迂, 會(huì)將載入數(shù)據(jù)所計(jì)算出的校驗(yàn)和與?check_sum?所記錄的校驗(yàn)和進(jìn)行對(duì)比, 以此來檢查 RDB 文件是否有出錯(cuò)或者損壞的情況出現(xiàn)器净。
3.1型雳、 databases部分
一個(gè) RDB 文件的?databases?部分可以保存任意多個(gè)非空數(shù)據(jù)庫。
每個(gè)非空數(shù)據(jù)庫的RDB文件都可以保存為?SELECTDB?、?db_number?四啰、?key_value_pairs?三個(gè)部分
SELECTDB?常量的長(zhǎng)度為?1?字節(jié)宁玫, 當(dāng)讀入程序遇到這個(gè)值的時(shí)候, 它知道接下來要讀入的將是一個(gè)數(shù)據(jù)庫號(hào)碼柑晒。
db_number?保存著一個(gè)數(shù)據(jù)庫號(hào)碼欧瘪, 根據(jù)號(hào)碼的大小不同, 這個(gè)部分的長(zhǎng)度可以是?1?字節(jié)匙赞、?2?字節(jié)或者?5?字節(jié)佛掖。 當(dāng)程序讀入?db_number?部分之后, 服務(wù)器會(huì)調(diào)用?SELECT?命令涌庭, 根據(jù)讀入的數(shù)據(jù)庫號(hào)碼進(jìn)行數(shù)據(jù)庫切換芥被, 使得之后讀入的鍵值對(duì)可以載入到正確的數(shù)據(jù)庫中。
key_value_pairs?部分保存了數(shù)據(jù)庫中的所有鍵值對(duì)數(shù)據(jù)坐榆, 如果鍵值對(duì)帶有過期時(shí)間拴魄, 那么過期時(shí)間也會(huì)和鍵值對(duì)保存在一起。 根據(jù)鍵值對(duì)的數(shù)量席镀、類型匹中、內(nèi)容、以及是否有過期時(shí)間等條件的不同豪诲,?key_value_pairs?部分的長(zhǎng)度也會(huì)有所不同顶捷。key_value_pairs具體編碼。