1.緒論
壓縮列表是redis最底層的結構之一,比如redis中的hash,list在某些場景下使用的都是壓縮列表。接下來就讓我們看看壓縮列表結構究竟是怎樣的。
2.ziplist
2.1 ziplist的組成
在低版本中壓縮列表是由ziplist實現的,我們來看看他的結構
可以看出壓縮列表由如下幾個字段組成:
1.zlbytes:4個字節的總長度;
2.zltail: 4個字節最后一個元素的指針;
3.zllen:2個字節總的元素個數;
4.多個entry元素;
5.zlend:壓縮列表的結尾標志。
每個entry元素由3部分組:
1.previous_entry_length:1個字節或者5個字節,上一個entry的長度,當上一個元素大小小于255個自己,當前字段為1個字節,當超過255個字節,當前字段為5個字節;
2.encoding:通過1個字節,用來表示存儲的內容是什么類型,比如int16或者int32,或者是字符串數組;
3.content:真正存儲的內容數據,如果是存儲的字符串,會存儲字符串的長度和內容。
2.2 ziplist的缺點
2.2.1?連鎖更新
ziplist為了解決從節點后向前遍歷的問題,所以每個entry都存儲了前一個節點的長度previous_entry_length,而redis一直秉持著對節約內存的優秀品質,如果前一個節點的數量小于255個字節,就用1個字節來存儲長度,但是大于的話就用5個字節來存儲長度。現在假設ziplist有5個entry,而且剛好5個entry的長度254,剛好每個previous_entry_length都是一個字節來存儲長度,現在假設第一個entry加了一些數據,導致長度,大于了255個字節,第二個元素的previous_entry_length需要用5個字節來存儲前一個元素的長度,導致第二個entry的總長度也增加了,并且超過了255個字節,所以第3個元素的previous_entry_length也需要用5個字節存儲上一個元素的長度,依此類推,修改一個元素的內容,需要修改后面所有的元素。這就是連鎖更新。
3.listpack
在高版本的redis中,為了解決連鎖更新問題,redis采用listpack來實現壓縮列表。listpack和ziplist差不多,但是有個區別就是每個entry記錄的是本entry的長度,而不是上一個entry的長度,所以每個entry長度的改變只會影響自己,而不會影響到其他的entry。
3.1 listpack的組成
1.tot-bytes:4個字節的總長度
2.num-elements:entry的總個數
3.多個entry
4.end-bytes:1個字節的結束標識
每個entry由3部分組成:
1.encoding:1個字節,用來標識content存儲的內容的編碼,整數或者字符串
2.content:每個entry存儲的內容
3.back-len:當前entry的長度,這是和ziplist的主要區別