Redis中的數據結構與內部編碼

?

? 本篇文章主要是對 Redis 常見的數據結構進行講解,同時還對其所對應的不同的內部編碼進行講解。希望本篇文章會對你有所幫助。

文章目錄

一、五大數據結構

二、數據結構對應的編碼方式

String

hash

list

set

zset


🙋?♂??作者:@Ggggggtm?🙋?♂?

👀?專欄:Redis 👀

💥?標題:Redis中的數據結構與內部編碼 💥

????寄語:與其忙著訴苦,不如低頭趕路,奮路前行,終將遇到一番好風景???

? 我們知道,redis是支持不同的數據類型的,而不同的數據類型底層所采用的數據結構也有所差異,同時不同的數據結構也會有不同的操作指令。我們這里所說的不同的數據類型都是指的value的類型,而key的類型固定是string的。上篇文章講解到的type指令,其返回值是key所對應的value的數據類型!

一、五大數據結構

? ?Redis的鍵值對中,value所用到的五種主要的數據結構,它們分別是:

  1. String(字符串):最基本的類型,可以包含任何形式的數據,比如一個文本、JSON字符串或者二進制數據。

  2. List(列表):一個有序的字符串列表,元素的順序由插入順序決定,可以在兩端進行插入和刪除操作。

  3. Set(集合):一個不重復且無序的字符串集合,可對集合中的元素進行添加、刪除和判斷某個元素是否存在的操作。

  4. Hash(哈希表):類似于關聯數組,包含字段和與其對應的值,常用于存儲對象。

  5. Zset(有序集合):類似于集合,但每個元素都關聯一個分數,可以按照分數進行排序,適合構建排行榜等功能。

? 具體可看下圖:

??

? Redis 底層在實現上述數據結構的時候,會在源碼層面針對上述實現進行特定的優化,來達到節省時間或者節省空間的效果。簡單來說,數據結構的內部具體實現不是固定統一的,會根據不同的情況,redis會自動適配合適的數據結構。但是每個數據結構的底層實現有固定的幾種方式。

? 舉個例子,redis承諾現在我這有個hash表,你進行查詢、插入、刪除操作都保證O(1)的書簡復雜度。但是這個背后的實現,不一定就是一個標準的hash表。可能再特定場景下,使用別的數據結構實現。但是仍然保證時間復雜度符合承諾。

? 那么哦我們現在就會有兩個大致方向上的理解:

  • 數據結構是指redis 承諾給你的。也可以理解成數據類型;
  • 編碼方式是redis內部底層的實現;
  • 一個數據結構有對應固定的編碼方式。

二、數據結構對應的編碼方式

? 實際上每種數據結構都有自己底層的內部編碼實現,而且是多種實現這樣 Redis 會在合適的場景選擇合適的內部編碼。具體數據結構所對應的編碼方式如下:

數據結構內部編碼
string1.raw
2.embstr
3.int
hash1.hashtable
2.ziplist
list1.linkedlist
2.ziplist
set1.hashtable
2.intset
zset1.skiplist
2.ziplist

? 下面我們來詳細解釋一下不同的內部編碼。

String

? Redis中 String 的內部編碼有三種:int、raw、embstr。

  1. int編碼

    • 當字符串可以被解釋為整數時,Redis會將該字符串以int編碼進行存儲,節省內存空間。
    • int編碼使用64位有符號整數來表示,其范圍為-2^63到2^63-1。
    • 當字符串的值處于int編碼的范圍內時,Redis會使用int編碼來存儲,這樣可以減少內存占用并提高性能。
  2. raw編碼

    • 當字符串無法被解釋為整數時,Redis會以raw編碼進行存儲。
    • raw編碼使用簡單動態字符串(SDS)來表示,SDS是一種帶有緩沖區的字符串表示形式,可以動態擴展和收縮,適用于存儲任意長度的字符串數據。
    • raw編碼適用于存儲包含非整數數據的字符串,如文本、JSON、XML等。
  3. embstr編碼

    • embstr是一種特殊的內部編碼方式,用于存儲長度較短的字符串。
    • 當字符串長度在一定范圍內(默認為39字節)時,Redis會使用embstr編碼來存儲,以進一步減少內存開銷。
    • embstr編碼實際上將字符串值和其他元數據一起存儲在一個連續的內存塊中,節省了額外指針和分配內存的開銷。

? SDS動態字符串可參考文章:Redis(設計與實現):01---數據結構之SDS動態字符串(raw、embstr、int、struct sdshdr)_sds類型的int與raw查詢速度的區別

hash

??Redis 中的 Hash 類型可以使用兩種內部編碼方式:hashtable 和 ziplist。

  1. Hashtable:

    • Hashtable 是 Redis 中 Hash 類型的默認內部編碼方式。
    • 當 Hash 中包含的鍵值對數量較多,或者鍵值對的值較大時,Redis 會自動將 Hash 內部編碼為 Hashtable。
    • Hashtable 使用哈希表來存儲鍵值對,可以快速進行數據查找,適合處理大規模的數據。
  2. Ziplist:

    • Ziplist 是一種緊湊的數據結構,適合存儲小規模的數據。
    • 當 Hash 中包含的鍵值對數量較少,且每個鍵值對的鍵和值的長度都較小時,Redis 會選擇使用 Ziplist 進行內部編碼。
    • Ziplist 使用一段連續的內存空間來存儲鍵值對,節約了內存的使用,但查找效率沒有哈希表高。
    • 由于元素過少,通過遍歷,時間復雜度還是可以認為是 O(1)

? 總結來說,當 Hash 數據較大或者鍵值對較復雜時,Redis 會使用 Hashtable 進行內部編碼以獲得更好的性能;而當 Hash 數據較小且簡單時,Redis 會選擇使用 Ziplist 進行內部編碼以節約內存空間。

? 具體底層實現細節可參考文章:Redis(設計與實現):06---數據結構之壓縮列表(ziplist、struct ziplist)_4位長,介于0至12之間的無符號整數Redis(設計與實現):03---數據結構之字典(hashtable、struct dictht、struct dictEntry、struct dict)-CSDN博客

list

? 在 Redis 中,List 類型可以使用三種不同的內部編碼方式:linkedlist、ziplist 和 quicklist。

  1. Linkedlist(雙向鏈表):

    • linkedlist 內部編碼主要適用于 List 包含的元素數量較多,或者元素的大小較大的情況。它通過指針將元素連接在一起,支持快速的插入和刪除操作,適合處理大規模的數據。
  2. Ziplist(壓縮列表):

    • ziplist 內部編碼適用于 List 包含的元素數量較少,且每個元素的大小都比較小時。Ziplist 使用緊湊的數據結構來存儲元素,節約了內存的使用,但查找和修改操作的效率沒有 linkedlist 高。
  3. Quicklist(快速列表):

    • quicklist 是 Redis 為了優化 List 類型而引入的一種內部編碼方式。它實際上是將多個 ziplist 連接在一起形成的一個雙向鏈表結構。quicklist 既具備了 ziplist 節約內存空間的優點,又能夠快速地處理大規模的數據,同時還兼顧了快速的插入和刪除操作。

? 綜上所述,Redis 根據 List 中元素的數量和大小來選擇合適的內部編碼方式:linkedlist 適用于大規模數據的場景,ziplist 適用于節約內存的場景,而 quicklist 則是為了兼顧以上兩種場景而設計的一種高效內部編碼方式。大部分場景下都是使用的quicklist。

set

??在 Redis 中,Set 類型可以使用兩種不同的內部編碼方式:hashtable 和 intset。

  1. Hashtable(哈希表):

    • 當 Set 中的元素數量較多,或者元素較長時,Redis 會選擇使用 hashtable 內部編碼。這種編碼方式使用了哈希表結構來存儲元素,它提供了較快的查找、插入和刪除操作,適用于處理較大規模的數據。
  2. Intset(整數集合):

    • 當 Set 中的所有元素都是整數,并且數量較少時,Redis 會選擇使用 intset 內部編碼。intset 使用緊湊的數組結構來存儲整數元素,節省了內存空間的使用,并且提供了高效的操作,適用于存儲小規模的整數數據集。

? 在實際使用中,Redis 根據 Set 的特點(元素數量、元素類型等)來動態地選擇合適的內部編碼方式,以提高性能和節約內存空間。通過使用合適的內部編碼方式,Redis 能夠更好地滿足不同場景下對 Set 數據類型的需求。

? intset底層實現可參考文章:Redis(設計與實現):04---數據結構之整數集合(intset、struct intset)

zset

??在 Redis 中,有序集合(Sorted Set)類型可以使用兩種不同的內部編碼方式:skiplist 和 ziplist。

  1. Skiplist(跳躍表):

    • 當有序集合中的成員數量較多或者成員較長時,Redis 會選擇使用 skiplist 內部編碼。跳躍表是一種基于鏈表的數據結構,它可以提供快速的插入、刪除和查找操作。
    • Skiplist 編碼方式適用于處理較大規模的有序集合數據,因為它能夠保持較高的性能并且具有良好的平衡性能。
  2. Ziplist(壓縮列表):

    • 當有序集合中的成員數量較少且每個成員都比較短小精悍時,Redis 會選擇使用 ziplist 內部編碼。壓縮列表是一種緊湊的數據結構,可以節省內存空間,適用于存儲較小規模的有序集合數據。
    • Ziplist 內部編碼方式對于小型的有序集合數據具有較好的存儲效率和操作性能。

? 根據有序集合的實際情況,Redis 會動態地選擇合適的內部編碼方式,以便在不同場景下提供最佳的性能和內存利用率。

? skiplist底層實現原理可參考文章:Redis(設計與實現):05---數據結構之跳躍表(skiplist、struct zskiplistNode、struct zskiplist)_skiplist和zskiplistnode

? 可以看到每種數據結構都有至少兩種以上的內部編碼實現,例如list數據結構包含了linkedlist和ziplist 兩種內部編碼。同時有些內部編碼,例如ziplist,可以作為多種數據結構的內部實現,可以通過object encoding命令查詢內部編碼:

? ?Redis這樣設計有兩個好處:

  • 可以改進內部編碼,而對外的數據結構和命令沒有任何影響,這樣一旦開發出更優秀的內部編碼,無需改動外部數據結構和命令,例如Redis 3.2提供了quicklist,結合了ziplist和linkedlist兩者的優勢,為列表類型提供了一種更為優秀的內部編碼實現,而對用戶來說基本無感知。
  • 多種內部編碼實現可以在不同場景下發揮各自的優勢,例如ziplist 比較節省內存,但是在列表元素比較多的情況下,性能會下降,這時候Redis 會根據配置選項將列表類型的內部實現轉換為linkedlist,整個過程用戶同樣無感知。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/18697.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/18697.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/18697.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

js 面試題學習筆記一

1、什么是防抖和節流?有什么區別?如何實現? 防抖:觸發高頻事件后N秒內函數只會執行一次,如果N秒高頻事件再次被觸發,則重新計算時間。(a時間觸發,5秒內執行一次,但是第4…

10G UDP協議棧 (9)UDP模塊

目錄 一、UDP協議簡單介紹 二、UDP功能實現 三、仿真 一、UDP協議簡單介紹 UDP協議和TCP協議同位于傳輸層,介于網絡層(IP)和應用層之間:UDP數據部分為應用層報文,而UDP報文在IP中承載。 UDP 報文格式相對于簡單&am…

電腦出現:excel詞典(xllex.dll)文件丟失或損壞的錯誤提示怎么辦?有效的將丟失的xllex.dll修復

當遇到 Excel 提示“詞典 (xllex.dll) 文件丟失或損壞”的問題時,通常意味著該動態鏈接庫文件(Dynamic Link Library,DLL),它與拼寫檢查功能相關聯的,無法被正確找到或者合適地使用。那么有什么辦法可以解決…

LLVM技術在GaussDB等數據庫中的應用

目錄 LLVM和數據庫 LLVM適用場景 LLVM對所有類型的SQL都會有收益嗎? LLVM在OLTP中就一定沒有收益嗎? GaussDB中的LLVM 1. LLVM在華為應用于數據庫的時間線 2. GaussDB LLVM實現簡析 3. GaussDB LLVM支持加速的場景 支持LLVM的表達式&#xff1a…

vue項目出現多次ElMessage

問題: 解決方法: let message null if (message null) { message ElMessage.error(“登錄過期,請重新登錄”); } 最終效果:只出現一個彈框

Orange AIpro Color triangle幀率測試

OpenGL概述 OpenGL ES是KHRNOS Group推出的嵌入式加速3D圖像標準,它是嵌入式平臺上的專業圖形程序接口,它是OpenGL的一個子集,旨在提供高效、輕量級的圖形渲染功能。現推出的最新版本是OpenGL ES 3.2。OpenGL和OpenCV OpenCL不同,…

實操專區-第15周-課堂練習專區-漏斗圖與金字塔圖

實操專區-第15周-課堂練習專區-漏斗圖 下載安裝ECharts,完成如下樣式圖形。 代碼和截圖上傳 基本要求:下圖3選1,完成代碼和截圖 完成 3.1.3.16 漏斗圖中的任務點 基本要求:2個選一個完成,多做1個加2分。 請用班級學號姓…

銀行對公貸款軟件業務流程詳解

對公貸款業務是指商業銀行向企事業單位提供資金支持,用于資本擴充、生產經營、項目建設等方面的融資。其目的在于支持企事業單位的發展,推動經濟增長。通過提供資金支持,企事業單位可以獲得必要的資金來擴大生產規模、提高生產能力、研發新產…

第8周 分布式事務與數據一致性主流解決方案落地

第8周 分布式事務與數據一致性主流解決方案落地 1. 最終一致性原理與解析2. 微服務的解耦3. 本地消息存儲4. 自定義事務管理器5. 本地消息刪除********************************************************************************** 本周拓展數據的一致性落地,采用弱…

【Java EE】網絡原理——HTTP請求

目錄 1.認識URL 2.認識“方法(method)” 2.1GET方法 2.1.1使用Fiddler觀察GET請求 2.1.2 GET請求的特點 2.2 POST方法 2.2.1 使用FIddler觀察POST方法 2.2.2 POST請求的特點 3.認識請求“報頭”(header) 3.1 Host 3.2 C…

Spring MVC 工作流程源碼分析

前言: 我們知道 Spring MVC 的核心是前端控制器 DispatcherServlet,客戶端所有的請求都會交給 DispatcherServlet 來處理,本篇我我們來分析 Spring MVC 處理客戶端請求的流程,也就是工作流程。 Sping MVC 只是儲備傳送門&#x…

Java整合EasyExcel實戰——3(上下列相同合并單元格策略)

參考&#xff1a;https://juejin.cn/post/7322156759443095561?searchId202405262043517631094B7CCB463FDA06https://juejin.cn/post/7322156759443095561?searchId202405262043517631094B7CCB463FDA06 準備條件 依賴 <dependency><groupId>com.alibaba</gr…

鄰接矩陣廣度優先遍歷

關于圖的遍歷實際上就兩種 廣度優先和深度優先&#xff0c;一般關于圖的遍歷都是基于鄰接矩陣的&#xff0c;考試這些&#xff0c;用的也是鄰接矩陣。 本篇文章先介紹廣度優先遍歷的原理&#xff0c;和代碼實現 什么是圖的廣度優先遍歷&#xff1f; 這其實和二叉樹的層序遍…

新人學習筆記之(數組1)

一、數組的概念 1.數組&#xff08;Array&#xff09;可以把一組相關的數據一起存放&#xff0c;并提供方便的訪問&#xff08;獲取&#xff09;方式 2.數組是指一組數據的集合&#xff0c;其中的每個數據被稱作元素&#xff0c;在數組中可以存放任意類型的元素&#xff0c;數組…

數據結構——二叉樹的基本應用

在此之前我們已經初步了解了二叉樹&#xff0c;在介紹堆的基本應用時&#xff0c;我們已經具體介紹了完全二叉樹的基本應用&#xff0c;本章我們介紹二叉樹的基本應用&#xff0c;這個不止指的是完全二叉樹&#xff0c;而是指泛型的二叉樹。 二叉樹的基本應用&#xff0c;由于…

代碼隨想錄算法訓練營第54天|● 392.判斷子序列 ● 115.不同的子序列

392. 判斷子序列 這個微軟面試的時候考過 雙指針就行 編輯距離入門題&#xff1a; 思路是一樣的 相同字符1 否則從前面順下來 class Solution:def isSubsequence(self, s: str, t: str) -> bool:dp[[0]*(len(t)1) for _ in range(len(s)1)]for i in range(1,len(s)1):f…

aspose-*的使用

文章目錄 aspose-*一、依賴--maven二、需求1、word------>pdf2、doc------>docx2、xls------>xlsx aspose-* 一、依賴–maven 備注&#xff1a;第三方的jar包可以從資源中下載&#xff0c;有上傳的 <!--aspose依賴--><dependency><groupId>aspose…

刷代碼隨想錄有感(81):貪心算法——分發餅干

題干&#xff1a; class Solution { public:int findContentChildren(vector<int>& g, vector<int>& s) {sort(g.begin(), g.end());sort(s.begin(), s.end());int index s.size() - 1;int res 0;for(int i g.size() - 1; i > 0; i--){if(index >…

GitLab項目中添加用戶,并設置其角色權限等

注意&#xff1a;創建用戶(new user)&#xff0c;創建完用戶然后再項目邀請用戶&#xff0c;選擇創建過的用戶 一、以管理員身份登錄GitLab的WebUI并創建用戶 1>.使用管理員登錄GitLab 使用管理員(root)用戶登錄成功后&#xff0c;點擊如下圖所示的小扳手&#xff0c;點擊…

java 反射的用法

下面是一個簡單的Java反射示例&#xff0c;演示了如何使用反射機制獲取類的信息并調用其方法&#xff1a; import java.lang.reflect.Method;class MyClass {private String name;public void setName(String name) {this.name name;}public String getName() {return name;}…