redis 是基于內(nèi)存讀寫的數(shù)據(jù)庫,所有數(shù)據(jù)都存儲在內(nèi)存中止潮,所以存儲的數(shù)據(jù)大小受到了限制柒莉。但redis依然提供了固化功能,與mysql沽翔,leveldb等數(shù)據(jù)庫不同的是兢孝,redis的存儲功能只是用做備份,恢復(fù)的功能,全量數(shù)據(jù)還是存儲在內(nèi)存中仅偎。
redis內(nèi)部提供了兩種固化數(shù)據(jù)的方式,aof 和rdb橘沥。
1.aof
數(shù)據(jù)寫入
aof全稱appendOnlyFile,要讓redis支持aof方式座咆,需要將配置文件的appendonly配置為"yes"痢艺,并配置appendfsync 為everysec/always/no。everysec是redis推薦的配置介陶,我們默認以這種方式來具體分析堤舒。
每次對數(shù)據(jù)有修改的操作,均會以append的方式寫入server.aof_buf中哺呜,每秒鐘將在時間事件中檢查這個緩沖區(qū)是否為空舌缤,不空則說明有新的更新,將其寫入aof文件中(注意write函數(shù)并非實時寫入硬盤某残,可以用flush函數(shù)來強制刷新未寫入的緩存),并觸發(fā)刷新任務(wù)玻墅,通知bio模塊創(chuàng)建的線程中執(zhí)行介牙。aof的文件是相對"白話"的澳厢,如圖是我本地截取的aof文件:
'*'后跟的是當前的參數(shù)個數(shù)环础,'$'后跟的是下一個參數(shù)的長度,再后來就是參數(shù)了喳整。一個redis中有多個數(shù)據(jù)庫裸扶,我們需要確定數(shù)據(jù)增改到那個數(shù)據(jù)庫了框都,因此第一句為select db的操作。
除了手動配置的刷新aof規(guī)則外魏保,客戶端可以手動觸發(fā)bgrewriteaof來覆蓋已有的aof文件(未開啟aof配置也是支持這個命令),客戶端發(fā)起此命令后摸屠,redis會fork一個子進程來將內(nèi)存中的數(shù)據(jù)保存到文件中。那么問題來了季二,子進程運行過程中檩咱,redis主進程依然在提供服務(wù)胯舷,如果期間寫入新的數(shù)據(jù)刻蚯,那么主子進程間的數(shù)據(jù)將會不同步桑嘶,如何解決炊汹?期間的數(shù)據(jù)會存儲在鏈表數(shù)據(jù)塊server.aof_rewrite_buf_blocks中逃顶,當主進程用wait方法檢測到子進程退出以后讨便,會調(diào)用backgroundRewriteDoneHandler函數(shù)以政,將緩存的數(shù)據(jù)附加到新的aof文件中霸褒。重寫aof可以減小aof文件的大小,因為部分數(shù)據(jù)失效傲霸,或者來回更改,在everysec的配置中均會保存下來眉反,但是重寫aof之后,無效數(shù)據(jù)寸五,或者中間狀態(tài)的修改均會被忽略梳凛。
數(shù)據(jù)載入
redis剛啟動的時候會優(yōu)先檢查是否開啟aof配置(否則rdb)梳杏,如果是則加載aof配置文件韧拒,每個參數(shù)均以'\n'結(jié)尾,因此讀取/判斷合法十分方便叛溢。創(chuàng)建一個fakeClient來模擬客戶端將數(shù)據(jù)插入內(nèi)存中。這里有一個疑問楷掉,數(shù)據(jù)載入的同時厢蒜,服務(wù)依然處理客戶端的io任務(wù),這樣不怕aof的舊文件寫臟用戶新插入的數(shù)據(jù)么烹植。
2.rdb
數(shù)據(jù)寫入
用戶可以配置redis中save的參數(shù)斑鸦,格式為save sec commit 代表每sec秒,如果有commit次修改草雕,則由服務(wù)自身執(zhí)行一次bgsave操作巷屿。save配置可以有多個,相互之間是或的關(guān)系墩虹。server.dirty用來記錄數(shù)據(jù)修改次數(shù),bgsave完成以后诫钓,會將其置0浓冒。
redis的每次寫入都是全量操作尖坤,步驟如下
1.創(chuàng)建臨時文件稳懒,寫入redis字符串+版本號慢味。
2.寫入select db語句场梆,如果當次db沒有數(shù)據(jù)纯路,跳到下一個或油,沒有更多數(shù)據(jù)庫了驰唬,跳到步驟5顶岸。
3.創(chuàng)建字典的迭代器叫编,循環(huán)字典內(nèi)的元素辖佣。
4.redis都是鍵值對數(shù)據(jù)搓逾,分別寫入超時時間(如果有的話)卷谈,value的類型霞篡,key世蔗,value,其中key和value盡可能的壓縮編碼污淋。如果迭代器到達結(jié)尾顶滩,跳到步驟2寸爆。
5.大于4的版本加入了校驗碼胳泉,校驗和使用crc計算爹脾,用臨時文件覆蓋正式rdb文件找田,流程結(jié)束歌憨。
數(shù)據(jù)載入
這個也沒有懸念了墩衙,怎么寫入务嫡,就怎么加載漆改;讀取到數(shù)據(jù)之后直接調(diào)用dbAdd函數(shù)把數(shù)據(jù)插入到字典server.db[dbnum]->dict中心铃。
對比下aof和rdb挫剑。
1.aof文件相對于直接保存了語句和中間過程去扣。所以更易于開發(fā)者修改查看數(shù)據(jù)樊破。追加修改的命令愉棱,對io哲戚,cpu奔滑,內(nèi)存壓力均較小顺少,相對來說更吃存儲空間朋其。
2.aof的缺點就是rdb的優(yōu)點了脆炎。特別是如果rdb的save參數(shù)保存不當梅猿,redis會頻繁執(zhí)行bgsave命令秒裕,每次都是全量修改粒没,在數(shù)據(jù)量大簇爆,修改頻繁的時候會是個災(zāi)難癞松。