首页
/
每日頭條
/
科技
/
redis數據結構與持久化
redis數據結構與持久化
更新时间:2024-11-11 17:39:03

redis數據結構與持久化(Redis數據結構-整數集合)1

一、回顧

通過對Redis的數據結構學習,簡單回顧一下數據結構在Redis中的實現有哪些?

簡單動态字符串(SDS),它用于Redis字符串鍵值對的底層實現。

鍊表,它是列表鍵的底層實現之一,以及發布、訂閱、慢查詢、監視器等。

字典,它是哈希鍵的底層實現之一,以及Redis數據庫的底層實現。

跳躍表,它是有序集合鍵的底層實現之一。

通過以上的數據結構學習,基本上覆蓋了Redis中所支持的五大數據類型,字符串、列表、哈希、集合、有序集合的底層實現。

那麼今天,要繼續學習的是,Redis中的另外兩個數據結構。

整數集合,它是集合鍵的底層實現之一。

壓縮列表,它是列表鍵和哈希鍵的底層實現之一。

redis數據結構與持久化(Redis數據結構-整數集合)2

二、整數集合

整數集合是Redis用于保存整數值的集合抽象數據結構。它支持編碼為 int16、int32、int64 的整數值。存儲元素的值必須唯一。

#每個 intset.h/intset結構表示一個整數集合 typedef struct intset { #編碼方式 uint32_t encoding; #集合包含的元素數量 uint32_t length; #保存元素的數組 int8_t contents[]; }intset;

contents 數組是整數集合的底層實現,整數集合的每個元素都是contents數組的一個數組項。各個項從小到大的排序,并且每個項元素值唯一。

length 屬性記錄了整數集合包含元素的數量,即contents的長度。

encoding 屬性的值為 INTSET_ENC_INT16、INTSET_ENC_INT32,INTSET_ENC_INT64

如果encoding 的值為INTSET_ENC_INT16,則 contents 就是一個 int16_t類型的數組,數組内都是 int16_t類型的整數值。範圍(-32768 至 32767)

如果encoding 的值為INTSET_ENC_INT32,則 contents 就是一個 int32_t類型的數組,數組内都是 int32_t類型的整數值。範圍(-2147483648 至 2147483647)

如果encoding 的值為INTSET_ENC_INT64,則 contents 就是一個 int64_t類型的數組,數組内都是 int64_t類型的整數值(-9223372036854775808 至 9223372036854775807)

redis數據結構與持久化(Redis數據結構-整數集合)3

例如上圖是一個整數集合,集合中的編碼為 int16_t 所以,contents 的數組項的大小需要在編碼為 int16 的範圍之内。

三、整數集合-升級

假設我們有一個整數集合,并且這個整數集合的編碼為 int16_t

此時,我們需要将一個 int32_t 的數據項存儲到該整數集合中。應該發生哪些動作呢?

1)對整數集合進行升級

2)再将新元素添加到整數集合中

3.1 升級整數集合一般需要三個步驟

  • 根據新元素的類型,擴展整數集合底層數組的空間大小,并為新元素分配空間
  • 将底層數組現有的元素都轉換成新元素相同的類型,再将轉換後的元素存儲到正确的位置上,并從小到大排列
  • 将新元素添加到底層數組中

因為每次向整數集合中添加新的元素都有可能發生升級,而每次升級都需要對底層數組中的元素進行類型轉換。所以,整數集合添加新元素需要升級的時間複雜度為O(n) 。

3.2 升級的好處

  • 提升整數集合的靈活性

因為,C語言是靜态類型語言,為了避免類型錯誤,不支持兩種不同數據類型的值放在同一個數據結構中。

在整數集合中,就可以将多種類型元素,存儲到同一個整數集合中。因為整數集合底層采用類型升級方案,即便你使用 int16 位、還是 32、64位的編碼方式,都可通過向上升級的方式解決類型不一緻的問題。

  • 盡可能的節約内存

因為,整數集合可以同時保存三種不同類型的值。又可以确保升級操作,隻會在有需要的時候進行升級,這可以盡量節省内存。

3.3 重點回顧

  • 整數集合是集合鍵的底層實現之一。
  • 整數集合的底層實現為數組,這個數組以有序、無重複的方式保存集合元素,在有需要時,會對數組進行類型升級。
  • 升級操作為整數集合帶來了操作上的靈活性,并盡可能的節約了内存。
  • 整數集合隻支持升級操作,不支持降級操作。

四、壓縮列表

壓縮列表是Redis為了節約内存而開發的,是由一系列特殊編碼的連續内存塊組成的順序型數據結構。和數組數據結構不同的是,大小可變、類型可變。

列表鍵的底層實現之一就有鍊表,那麼,為什麼有了鍊表數據結構,還會有一個壓縮列表呢?因為,節省内存呀!

鍊表中的每個節點都需要維護指針,相當占用内存。如果列表中存儲的元素比較少,字符串也比較短,如果采用了鍊表作為底層實現,是沒有必要的。

壓縮列表最擅長的是,存儲字符串相對較短,元素個數相對較少的數據場景。畢竟,壓縮列表底層存儲的是一塊連續的内存空間,除了所存儲的元素以為,沒有任何多餘的空閑空間。

所以當列表鍵和哈希鍵隻包含少量鍵值對,并且每個鍵值對都是小整數或長度較短的字符串時,就可以采用壓縮列表來作為底層實現。

4.1 壓縮列表結構

#壓縮列表數據結構 struct ziplist { #整個壓縮列表占用的字節數 int32zlbytes; #最後一個元素距離壓縮列表起始位置的偏移量,用戶快速定位最後一個節點 int32 zlbail_offset; #元素個數 int16 zllength; #元素内容列表、依次緊湊存儲 T[] entries; #标志壓縮列表的結束,值為OxFF int8 zlend; }

redis數據結構與持久化(Redis數據結構-整數集合)4

一個壓縮列表可以包含任意多個節點,每個節點保存一個字節數組或一個整數值。

zlbytes 屬性記錄着整個壓縮列表,占用的内存字節數,對壓縮列表進行重分配,或計算zlend的位置時使用。

zltail 屬性記錄壓縮列表,表尾節點距離壓縮列表的起始地址有多少字節,确定表尾節點地址。

zllen 屬性記錄壓縮列表,包含節點的數量,當這個屬性值小于UINT16_MAX(65535)時可信,否則需要遍曆整個壓縮列表獲得最新的長度。

entryX 屬性是壓縮列表,包含的各個節點,節點的長度由節點保存的内容決定。

zlend 屬性特殊值0xff(十進制255) 用于标記壓縮列表的末端。

4.2 壓縮列表-節點

每個壓縮列表節點都包含以下三個部分:

struct entry { # 前一個entry的字節長度 int prevlen; # 元素類型編碼 int encoding; #元素内容 optional byte[] content; }

redis數據結構與持久化(Redis數據結構-整數集合)5

1、previous_entry_length

previous_entry_length 屬性以字節為單位,記錄了壓縮列表中前一個節點的長度。

previous_entry_length 的屬性值的長度可以是 1 字節 也可以是 5 字節。

如果前一個節點的長度小于 254 則 length 的屬性值是 1 個字節。

如果前一個節點的長度大于 254 則 length 的屬性值是 5 個字節。

2、encoding

encoding 屬性記錄了節點的 content 屬性所保存數據的類型長度。

一個字節、兩個字節或五個字節的最高位是 00、01、10 的字節數組編碼。它意味着content 屬性保存着字節數組。數組的長度由編碼除去最高兩位之後的其他位記錄。

一字節長,值的最高位是 11 開頭的是整數編碼,此編碼表示節點 content 屬性保存着整數值。整數值的類型和長度由編碼除去最高兩位之後的其他位記錄。

3、content

content 屬性保存着節點的值,類型和長度由 encoding 和 length 決定,可以是一個字節數組或整數。

4.3 區分節點 數組、整數

壓縮列表中,所包含的多個節點,可以是一個長度受限的字符串數組(非結尾的字符串數組)也可以是一個整數。那怎麼區分這個節點存儲的是數組還是整數呢?

字符數組可以是以下三種長度的其中一種

  • 長度小于等于 63 字節的字符數組
  • 長度小于等于 16383 字節的字符數組
  • 長度小于等于 4294967295 字節的字符數組

整數值則是以下六種長度的其中一種

  • 4 位長,介于 0 至 12 之間的無符号整數
  • 1 字節長,有符合整數
  • 3 字節長,有符合整數
  • int16_t 類型整數
  • int32_t 類型整數
  • int64_t 類型整數

4.4 倒序遍曆

因為每個壓縮列表的節點中都存儲着一個 previous_entry_length 屬性。所以程序可以通過指針進行運算,根據當前節點的起始位置來計算出前一個節點的起始地址。

當前節點的地址-previous_entry_length=前一個節點起始地址

所以壓縮列表的為了支持雙向遍曆,通過 ztail_offset 這個字段來找到最後一個節點的地址,在通過上面的公式找到前一個節點地址,以此方法來進行倒序遍曆。

4.5、級聯更新

每個節點都有一個 previous_entry_length 屬性,它以字節為單位,并且是變長的,以253為臨界點,大于253用 5 個字節表示,小于或等于 則用 1 個字節表示。如果由 253 變成了 254 則會發生級聯更新。

如果每個節點都恰好存儲了253個字節内容,那麼修改第一個節點内容仍舊會導緻後續的節點發生級聯更新,

删除中間節點也會發生級聯更新

4.6 重點回顧

  • 壓縮類别是為了節省内存而開發的順序型數據結構
  • 列表鍵和哈希鍵的底層實現之一就是壓縮列表
  • 一個壓縮列表中包含了多個節點,每個節點可以保存一個字節數組或者整數值
  • 添加新節點到壓縮列表,或從中删除節點會引發級聯更新,但是概率比較小

五、參考文獻

《Redis 設計與實現》

《Redis 深度曆險》

,
Comments
Welcome to tft每日頭條 comments! Please keep conversations courteous and on-topic. To fosterproductive and respectful conversations, you may see comments from our Community Managers.
Sign up to post
Sort by
Show More Comments
推荐阅读
手機攝影小技巧你學會了嗎
手機攝影小技巧你學會了嗎
今天給攝影初學者講幾句拍攝思路和手機攝影該注意的事項,這是我去雲南深度遊出發前的最後一貼。這幾年我用手機拍了好多對手機攝影不夠了解的人認為似乎是不可能東西,比如動感效果的,瀑布溪流,夜景效果,以及飛鳥藏羚羊等,相對來說用手機拍攝這些題材時的...
2024-11-11
為什麼一些在qq裡的文件在電腦裡打不開
為什麼一些在qq裡的文件在電腦裡打不開
為什麼一些在qq裡的文件在電腦裡打不開?文件傳輸安全等級為高(阻止接收任何文件),下面我們就來聊聊關于為什麼一些在qq裡的文件在電腦裡打不開?接下來我們就一起去了解一下吧!為什麼一些在qq裡的文件在電腦裡打不開文件傳輸安全等級為高(阻止接收...
2024-11-11
4g手機值得買嗎
4g手機值得買嗎
現在買4G手機值得嗎?你聽到這個問題時的第一個反應會不會跟我一樣,現在還會有人買4G手機?都2022年還買4G手機幹啥,那不就是49年入國軍?對于買4G手機值不值得這個問題,我們先來看看市面上還有沒有4G手機可供選購。從一些電商平台和手機品...
2024-11-11
天津雲印章管理平台小程序
天津雲印章管理平台小程序
為進一步優化我市營商環境,為市場主體增添活力,依據《天津市電子印章管理暫行辦法》,天津市公安局深入推進“互聯網公安”智慧民生服務,天津市電子印章管理服務平台2020年11月11日正式上線運行,面向社會提供集電子印章申請、制作、簽章、驗章、查...
2024-11-11
現在怎麼升級win10系統
現在怎麼升級win10系統
win10系統新版本又更新了,最新的版本号Win10RS4(1803版);此次更新增加了時間線(Timeline)、專注助手(FocusAssist)、聽寫功能(Dictation)等新功能。如何第一時間體驗新版本的新功能呢?(一)升級前的...
2024-11-11
Copyright 2023-2024 - www.tftnews.com All Rights Reserved