好湿?好紧?好多水好爽自慰,久久久噜久噜久久综合,成人做爰A片免费看黄冈,机机对机机30分钟无遮挡

主頁 > 知識庫 > 壓縮列表犧牲速度來節省內存,Redis是膨脹了嗎

壓縮列表犧牲速度來節省內存,Redis是膨脹了嗎

熱門標簽:貴州電銷卡外呼系統 日本中國地圖標注 北京400電話辦理收費標準 山東外呼銷售系統招商 十堰營銷電銷機器人哪家便宜 超呼電話機器人 宿遷便宜外呼系統平臺 鄭州人工智能電銷機器人系統 魔獸2青云地圖標注

正常情況下我們選擇使用 Redis 就是為了提升查詢速度,然而讓人意外的是,Redis 當中卻有一種比較有意思的數據結構,這種數據結構通過犧牲部分讀寫速度來達到節省內存的目的,這就是 ziplist(壓縮列表),Redis 為什么要這么做呢?難道真的是覺得自己的速度太快了,犧牲一點速度也不影響嗎?

什么是壓縮列表

ziplist 是為了節省內存而設計出來的一種數據結構。ziplist 是由一系列特殊編碼組成的連續內存塊的順序型數據結構,一個 ziplist 可以包含任意多個 entry,而每一個 entry 又可以保存一個字節數組或者一個整數值。

ziplist 作為一種列表,其和普通的雙端列表,如 linkedlist 的最大區別就是 ziplist 并不存儲前后節點的指針,而 linkedlist 一般每個節點都會維護一個指向前置節點和一個指向后置節點的指針。那么 ziplist 不維護前后節點的指針,它又是如何尋找前后節點的呢?

ziplist 雖然不維護前后節點的指針,但是它卻維護了上一個節點的長度和當前節點的長度,然后每次通過長度來計算出前后節點的位置。既然涉及到了計算,那么相對于直接存儲指針的方式肯定有性能上的損耗,這就是一種典型的用時間來換取空間的做法。因為每次讀取前后節點都需要經過計算才能得到前后節點的位置,所以會消耗更多的時間,而在 Redis 中,一個指針是占了 8 個字節,但是大部分情況下,如果直接存儲長度是達不到 8 個字節的,所以采用存儲長度的設計方式在大部分場景下是可以節省內存空間的。

ziplist 的存儲結構

ziplist 的組成結構為:

zlbytes> zltail> zllen> entry> entry> ... entry> zlend>

其中 zlbyteszltailzllenziplisthead 部分,entryziplistentries 部分,每一個 entry 代表一個數據,最后 zlend 表示 ziplistend 部分,如下圖所示:

ziplist 中每個屬性代表的含義如下表格所示:

屬性 類型 長 度 說明
zlbytes uint32_t 4字節 記錄壓縮列表占用內存字節數(包括本身所占用的 4 個字節)。
zltail uint32_t 4字節 記錄壓縮列表尾節點距離壓縮列表的起始地址有多少個字節(通過這個值可以計算出尾節點的地址)
zllen uint16_t 2字節 記錄壓縮列表中包含的節點數量,當列表值超過可以存儲的最大值(65535)時,此值固定存儲 65535(即 216 次方 減 1),因此此時需要遍歷整個壓縮列表才能計算出真實節點數。
entry 節點 - 壓縮列表中的各個節點,長度由存儲的實際數據決定。
zlend uint8_t 1字節 特殊字符 0xFF(即十進制 255),用來標記壓縮列表的末端(其他正常的節點沒有被標記為 255 的,因為 255 用來標識末尾,后面可以看到,正常節點都是標記為 254)。

entry 存儲結構

ziplistheadend 存的都是長度和標記,而 entry 存儲的是具體元素,這又是經過特殊的設計的一種存儲格式,每個 entry 都以包含兩段信息的元數據作為前綴,每一個 entry 的組成結構為:

prevlen> encoding> entry-data>

prevlen

prevlen 屬性存儲了前一個 entry 的長度,通過此屬性能夠從后到前遍歷列表。 prevlen 屬性的長度可能是 1 字節也可能是 5 字節:

當鏈表的前一個 entry 占用字節數小于 254,此時 prevlen 只用 1 個字節進行表示。

prevlen from 0 to 253> encoding> entry>

當鏈表的前一個 entry 占用字節數大于等于 254,此時 prevlen5 個字節來表示,其中第 1 個字節的值固定是 254(相當于是一個標記,代表后面跟了一個更大的值),后面 4 個字節才是真正存儲前一個 entry 的占用字節數。

0xFE 4 bytes unsigned little endian prevlen> encoding> entry>

注意:1 個字節完全你能存儲 255 的大小,之所以只取到 254 是因為 zlend 就是固定的 255,所以 255 這個數要用來判斷是否是 ziplist 的結尾。

encoding

encoding 屬性存儲了當前 entry 所保存數據的類型以及長度。encoding 長度為 1 字節,2 字節或者 5 字節長。前面我們提到,每一個 entry 中可以保存字節數組和整數,而 encoding 屬性的第 1 個字節就是用來確定當前 entry 存儲的是整數還是字節數組。當存儲整數時,第 1 個字節的前兩位總是 11,而存儲字節數組時,則可能是 000110 三種中的一種。

當存儲整數時,第 1 個字節的前 2 位固定為 11,其他位則用來記錄整數值的類型或者整數值(下表所示的編碼中前兩位均為 11):

編碼 長度 entry保存的數據
11000000 1字節 int16_t類型整數
11010000 1字節 int32_t類型整數
11100000 1字節 int64_t類型整數
11110000 1字節 24位有符號整數
11111110 1字節 8位有符號整數
1111xxxx 1字節 xxxx 代表區間 0001-1101,存儲了一個介于 0-12 之間的整數,此時 entry-data 屬性被省略

注意:xxxx 四位編碼范圍是 0000-1111,但是 000011111110 已經被表格中前面表示的數據類型占用了,所以實際上的范圍是 0001-1101,此時能保存數據 1-13,再減去 1 之后范圍就是 0-12。至于為什么要減去 1 是從使用習慣來說 0 是一個非常常用的數據,所以才會選擇統一減去 1 來存儲一個 0-12 的區間而不是直接存儲 1-13 的區間。

當存儲字節數組時,第 1 個字節的前 2 位為 0001 或者 10,其他位則用來記錄字節數組的長度:

編碼 長度 entry保存的數據
00pppppp 1字節 長度小于等于 63 字節(6 位)的字節數組
01pppppp qqqqqqqq 2字節 長度小于等于 16383 字節(14 位)的字節數組
10000000 qqqqqqqq rrrrrrrr ssssssss tttttttt 5字節 長度小于等于 232 次方減 132 位)的字節數組,其中第 1 個字節的后 6 位設置為 0,暫時沒有用到,后面的 32 位(4 個字節)存儲了數據

entry-data

entry-data 存儲的是具體數據。當存儲小整數(0-12)時,因為 encoding 就是數據本身,此時 entry-data 部分會被省略,省略了 entry-data 部分之后的 ziplist 中的 entry 結構如下:

prevlen> encoding>

壓縮列表中 entry 的數據結構定義如下(源碼 ziplist.c 文件內),當然實際存儲并沒有直接使用到這個結構定義,這個結構只是用來接收數據,所以大家了解一下就可以了:

typedef struct zlentry {
 unsigned int prevrawlensize;//存儲prevrawlen所占用的字節數
 unsigned int prevrawlen;//存儲上一個鏈表節點需要的字節數
 unsigned int lensize;//存儲len所占用的字節數
 unsigned int len;//存儲鏈表當前節點的字節數
 unsigned int headersize;//當前鏈表節點的頭部大小(prevrawlensize + lensize)即非數據域的大小
 unsigned char encoding;//編碼方式
 unsigned char *p;//指向當前節點的起始位置(因為列表內的數據也是一個字符串對象)
} zlentry;

ziplist 數據示例

上面講解了大半天,可能大家都覺得枯燥無味了,也可能會覺得云里霧里,這個沒有關系,這些只要心里有個概念,用到的時候再查詢對應資料就可以了,并不需要全部記住,接下來讓我們一起通過兩個例子來體會一下 ziplist 到底是如何來組織存儲數據的。

下面就是一個壓縮列表的存儲示例,這個壓縮列表里面存儲了 2 個節點,節點中存儲的是整數 25

[0f 00 00 00] [0c 00 00 00] [02 00] [00 f3] [02 f6] [ff]
  |    |   |  |  |  |
 zlbytes  zltail  zllen "2"  "5" end

第一組 4 個字節為 zlbytes 部分,0f 轉成二進制就是 1111 也就是 15,代表整個 ziplist 長度是 15 個字節。第二組 4 個字節 zltail 部分,0c 轉成二進制就是 1100 也就是 12,這里記錄的是壓縮列表尾節點距離起始地址有多少個字節,也就是就是說 [02 f6] 這個尾節點距離起始位置有 12 個字節。第三組 2 個字節就是記錄了當前 ziplistentry 的數量,02 轉成二進制就是 10,也就是說當前 ziplist2 個節點。第四組 2 個字節 [00 f3] 就是第一個 entry00 表示 0,因為這是第 1 個節點,所以前一個節點長度為 0f3 轉成二進制就是 11110011,剛好對應了表格中的編碼 1111xxxx,所以后面四位就是存儲了一個 0-12位的整數。0011 轉成十進制就是 3,減去 1 得到 2,所以第一個 entry 存儲的數據就是 2。第五組 2 個字節 [02 f6] 就是第二個 entry02 即為 2,表示前一個節點的長度為 2,注意,因為這里算出來的結果是小于 254,所以就代表了這里只用到了 1 個字節來存儲上一個節點的長度(如果等于 254,這說明接下來 4 個字節才存儲的是長度),所以后面的 f6 就是當前節點的數據,轉換成二進制為 11110110,對應了表格中的編碼 1111xxxx,同樣的后四位 0110 存儲的是真實數據,計算之后得出是5。最后一組1個字節[ff]轉成二進制就是 11111111,代表這是整個 ziplist 的結尾。

假如這時候又添加了一個 Hello World 字符串到列表中,那么就會新增一個 entry,如下所示:

[02] [0b] [48 65 6c 6c 6f 20 57 6f 72 6c 64]

第一組的 1 個字節 02 轉成十進制就是 2 ,表示前一個節點(即上面示例中的 [02 f6])長度是 2。第 二組的2 個字節 0b 轉成二進制為 00001011,以 00 開頭,符合編碼 00pppppp,而除掉最開始的兩位 00,計算之后得到十進制 11,這就說明后面字節數組的長度是 11。第三組剛好是 11 個字節,對應了上面的長度,所以這里就是真正存儲了 Hello World 的字節數組。

ziplist 連鎖更新問題

上面提到 entry 中的 prevlen 屬性可能是 1 個字節也可能是 5 個字節,那么我們來設想這么一種場景:假設一個 ziplist 中,連續多個 entry 的長度都是一個接近但是又不到 254 的值(介于 250~253 之間),那么這時候 ziplist 中每個節點都只用了 1 個字節來存儲上一個節點的長度,假如這時候添加了一個新節點,如 entry1 ,其長度大于 254 個字節,此時 entry1 的下一個節點 entry2prelen 屬性就必須要由 1 個字節變為 5 個字節,也就是需要執行空間重分配,而此時 entry2 因為增加了 4 個字節,導致長度又大于 254 個字節了,那么它的下一個節點 entry3prelen 屬性也會被改變為 5 個字節。依此類推,這種產生連續多次空間重分配的現象就稱之為連鎖更新。同樣的,不僅僅是新增節點,執行刪除節點操作同樣可能會發生連鎖更新現象。

雖然 ziplist 可能會出現這種連鎖更新的場景,但是一般如果只是發生在少數幾個節點之間,那么并不會嚴重影響性能,而且這種場景發生的概率也比較低,所以實際使用時不用過于擔心。

總結

本文主要講解了 Redis 當中的 ziplist(壓縮列表),一種用時間換取空間的數據結構,在介紹壓縮列表存儲結構的同時通過一個存儲示例來分析了 ziplist 是如何存儲數據的,最后介紹了 ziplist 中可能發生的連鎖更新問題。

到此這篇關于壓縮列表犧牲速度來節省內存,Redis是膨脹了嗎的文章就介紹到這了,更多相關Redis壓縮列表內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • 詳解redis數據結構之壓縮列表
  • redis源碼分析教程之壓縮鏈表ziplist詳解

標簽:果洛 北京 楊凌 朝陽 吉安 大慶 臺州 江蘇

巨人網絡通訊聲明:本文標題《壓縮列表犧牲速度來節省內存,Redis是膨脹了嗎》,本文關鍵詞  壓縮,列表,犧牲,速度,來,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《壓縮列表犧牲速度來節省內存,Redis是膨脹了嗎》相關的同類信息!
  • 本頁收集關于壓縮列表犧牲速度來節省內存,Redis是膨脹了嗎的相關信息資訊供網民參考!
  • 推薦文章
    主站蜘蛛池模板: 男女插插插视频| 国产日产精品久久久久兰花| 国产茄子精品人妻无码A片| 小黄书一区二区三区不卡在线| 欧洲美女人**一级毛片| 欧美三级午夜理伦三级中视频| 欧洲VODAFONEWIFI大全| 国产女主播户外勾搭路人| 欧美日韩理论| 亚洲高清中文字幕| 9l熟女自拍蝌蚪9l视频成人| 国产一级无码AV999毛片| 网站免费黄色| 天堂电影网站| 长泰县| 性饥渴少妇XXXⅩOOOO| 免费看黄色三级毛片| 欧美亚洲综合另类在线观看| 黄色美容院在线| a级毛片视频免费观看| 白丝被弄羞涩娇喘动态图| 女的被?到爽羞羞免费| 亚洲国产欧美在线人成精品一区二区| 亚洲精品日韩中文字幕久久久| 深夜福利免费视频| 伊人色综合久久天天伊人| 一级特黄大片在线| 农村妇女一级毛片| 成年黄页网站视频全免费| 精品国产午夜激无码毛片| 亲妺妺的小泬让我进去 | 成人免费手机在线看网站| 情欲难抑小说| 色哟哟?入口国产精品| 免费三级手机在线现看| 97亚洲AV无码秘?蜜桃网| 爽灬爽灬好深灬免费视频| 性欧美zoz0另类xxxx| 宝宝我慢慢动不会很疼| 总裁做到失禁颤抖尿出来| 168人成色情网www|