Redis存儲機制分成兩種Snapshot和AOF。無論是那種機制,Redis都是將數(shù)據(jù)存儲在內存中。
Snapshot工作原理:是將數(shù)據(jù)先存儲在內存,然后當數(shù)據(jù)累計達到某些設定的伐值的時候,就會觸發(fā)一次DUMP操作,將變化的數(shù)據(jù)一次性寫入數(shù)據(jù)文件(RDB文件)。
AOF工作原理:是將數(shù)據(jù)也是先存在內存,但是在存儲的時候會使用調用fsync來完成對本次寫操作的日志記錄,這個日志揭露文件其實是一個基于Redis網(wǎng)絡交互協(xié)議的文本文件。AOF調用fsync也不是說全部都是無阻塞的,在某些系統(tǒng)上可能出現(xiàn)fsync阻塞進程的情況,對于這種情況可以通過配置修改,但默認情況不要修改。AOF最關鍵的配置就是關于調用fsync追加日志文件的平率,有兩種預設頻率,always每次記錄進來都添加,everysecond每秒添加一次。兩個配置各有所長后面分析。由于是采用日志追加的方式來持久話數(shù)據(jù),所以引出了第二個日志的概念:rewrite.后面介紹它的由來。
存儲模式性能和安全比較:
1.性能:Snapshot方式的性能是要明顯高于AOF方式的,原因有兩點:
采用2進制方式存儲數(shù)據(jù),數(shù)據(jù)文件比較小,加載快速.
存儲的時候是按照配置中的save策略來存儲,每次都是聚合很多數(shù)據(jù)批量存儲,寫入的效率很好,而AOF則一般都是工作在實時存儲或者準實時模式下。相對來說存儲的頻率高,效率卻偏低。
2.數(shù)據(jù)安全:AOL數(shù)據(jù)安全性高于Snapshot存儲,原因:
Snapshot存儲是基于累計批量的思想,也就是說在允許的情況下,累計的數(shù)據(jù)越多那么寫入效率也就越高,但數(shù)據(jù)的累計是靠時間的積累完成的,那么如果在長時間數(shù)據(jù)不寫入RDB,但Redis又遇到了崩潰,那么沒有寫入的數(shù)據(jù)就無法恢復了,但是AOF方式偏偏相反,根據(jù)AOF配置的存儲頻率的策略可以做到最少的數(shù)據(jù)丟失和較高的數(shù)據(jù)恢復能力。
說完了性能和安全,這里不得不提的就是在Redis中的Rewrite的功能,AOF的存儲是按照記錄日志的方式去工作的,那么成千上萬的數(shù)據(jù)插入必然導致日志文件的擴大,Redis這個時候會根據(jù)配置合理觸發(fā)Rewrite操作,所謂Rewrite就是將日志文件中的所有數(shù)據(jù)都重新寫到另外一個新的日志文件中,但是不同的是,對于老日志文件中對于Key的多次操作,只保留最終的值的那次操作記錄到日志文件中,從而縮小日志文件的大小。這里有兩個配置需要注意:
auto-aof-rewrite-percentage 100(當前寫入日志文件的大小占到初始日志文件大小的某個百分比時觸發(fā)Rewrite)
auto-aof-rewrite-min-size 64mb(本次Rewrite最小的寫入數(shù)據(jù)良)
兩個條件需要同時滿足。
2.Redis內存優(yōu)化理解
Redis內部有很多的數(shù)據(jù)類型,這些在官方文檔上都可以看到,下面是其內部優(yōu)化的一些細節(jié)點:
1.String和數(shù)字,在Redis中如果存儲的是“123”Redis是能夠識別出來這是一個數(shù)字并且按照數(shù)字來存儲,節(jié)省存儲空間,當然除了這個優(yōu)化之外,Redis內部會構建一個數(shù)字池,默認是10000,那么如果是在這個池子的數(shù)字就只需要用一個簡單的索引來引用進來就可以,而不需要把重復的數(shù)字都分開存儲。這個數(shù)值可以調整源代碼的宏:REDIS_SHARED_INTEGERS來擴大和縮小池子的大小。
2.復雜類型的存儲優(yōu)化,比如Map,List,Set等,這些集合都有一個特點可大可小,根據(jù)實際場景來定,一般情況下如果這些集合所包含的Entry不多,并且每個Entry所包含的Value不是很長的情況下,Redis內部使用緊湊格式來存儲數(shù)據(jù),緊湊格式存儲數(shù)據(jù)在查詢場景的算法復雜度是O(N),而類似Map或者Set他們的查詢算法復雜度都是O(1)那為什么要這么做呢?為了能夠節(jié)省內存空間,在N很小的時候其實和O(1)沒什么區(qū)別。所以這里不的不介紹緊湊格式的代表ZIPMap,他的數(shù)據(jù)結構是這樣:
可以看出,這個結構中初始情況只有2個字節(jié),隨著操作的增加它會變長,其中最關鍵的是一個關于Free這個字段的理解,以Map為例,如果新插入一個Key,那么對應ZipMap就會多出來一長串數(shù)據(jù):<len><key><len><free><value>。從圖中可以看到插入key1的時候只有綠色的一串,當key2插入的時候就會又出來一個類似的黃色結構串。free的功能是在插入的時候用來冗余空間的,當key所對應的數(shù)值發(fā)生變化的時候,如果數(shù)據(jù)變的比之前短了,那么free的長度就變大,這個時候不需要做ZipMap的resize操作,如果數(shù)據(jù)長度變長了,并且在free能夠足以支持新數(shù)據(jù)的范圍之內,那么free就被利用起來,并且也不需要做Resize。這個時候會有空間的浪費或者說碎片??臻g換時間,沒什么好說的。當然Redis的代碼中還有另外一個參數(shù)ZIPMAP_VALUE_MAX_FREE,這個參數(shù)可以用來設置如果Free的大小超過了這個值,那么ZipMap會發(fā)生Resize(收縮),從而節(jié)約空間