小對象壓縮

鑑於Redis是純內存數據庫,爲了儘可能的節省內存開銷避免因爲內存不足而崩潰,Redis對一部分數據結構進行了優化。

編譯

如果使用32位進行編譯,內部所有數據結構所使用的指針空間佔用會少一半,如果使用內存不超過4G,可以考慮使用32位進行編譯,如果不足還可以通過增加實例的方式來解決。

壓縮

這裏有個ziplist技術,可以說道說道。當集合數據結構很小的話,那麼它會使用緊湊存儲形式壓縮存儲。

ziplist是類似於字節數組結構的壓縮列表,列表中每個元素僅僅相鄰:

該數組[0]佔4字節,標記存儲整個ziplist佔用的總字節數。

該數組[1]佔4字節,標記最後一個entry的偏移量,方便直接定位尾部元素。

該數組[2]佔2字節,ziplist中entry的數量。

該數組[length-1]佔1字節,內容就是255用來標記結束。

數組其他元素都是entry。

其實,ziplist、 intset爲了解除集合數據結構很少的時候而採取的方法。

intset跟ziplist類似,是一個緊湊的整數數組結構,它用於存放元素都是整數的並且元素個數較少的 set 集合。如果整數可以用 uint16 表示,那麼 intset 的元素就是 16 位的數組,如果新加入的整數超過了 uint16 的表示範圍,那麼就使用 uint32 表示,如果新加入的元素超過了 uint32 的表示範圍,那麼就使用 uint64 表示,Redis 支持 set 集合動態從 uint16 升級到 uint32,再升級到 uint64。

當集合對象的元素不斷增加或者某個value值過大,這種小對象存儲也會被升級爲標準結構。Redis規定在小對象存儲結構的限制條件如下:

hash-max-zipmap-entries 512 # hash 的元素個數超過 512 就必須用標準結構存儲

hash-max-zipmap-value 64 # hash 的任意元素的 key/value 的長度超過 64 就必須用標準結構存儲

list-max-ziplist-entries 512 # list 的元素個數超過 512 就必須用標準結構存儲

list-max-ziplist-value 64 # list 的任意元素的長度超過 64 就必須用標準結構存儲

zset-max-ziplist-entries 128 # zset 的元素個數超過 128 就必須用標準結構存儲

zset-max-ziplist-value 64 # zset 的任意元素的長度超過 64 就必須用標準結構存儲

set-max-intset-entries 512 # set 的整數元素個數超過 512 就必須用標準結構存儲

說白了,就是Redis可以控制小對象壓縮與標準結構存儲之間轉換。

內存回收

Redis並不總是可以將空閒內存立即歸還給操作系統。

原因是操作系統回收內存是以頁爲單位,如果這個頁上只要有一個key還在使用,那麼它就不能被回收。key分散到了很多頁面中,每個頁面都還有其它key存在,這就導致了內存不會立即被回收。

如果執行flushdb,然後再觀察內存會發現內存確實被回收了。原因是所有的key都幹掉了,大部分之前使用的頁面都完全乾淨了,會立即被操作系統回收。Redis雖然無法保證立即回收已經刪除的 key的內存,但是它會重用那些尚未回收的空閒內存。

Redis爲了保持自身結構的簡單性,在內存分配這裏直接讓第三方內存分配庫去實現。目前 Redis 可以使用 jemalloc(facebook) 庫來管理內存,也可以切換到tcmalloc(google)。因爲 jemalloc 相比 tcmalloc的性能要稍好一些,所以Redis默認使用了jemalloc。

發佈了167 篇原創文章 · 獲贊 10 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章