深入淺出Redis(一):對象與數據結構

引言

Redis是一款基于鍵值對的數據結構存儲系統,它的特點是基于內存操作、單線程處理命令、IO多路復用模型處理網絡請求、鍵值對存儲與簡單豐富的數據結構等等

這篇文章主要圍繞Redis中的對象與數據結構來詳細說明鍵值對存儲與簡單豐富的數據結構這兩大特點

Redis中的數據以Key,Value鍵值對的形式存儲在字典中,字典的實現是哈希表

鍵Key只能使用字符串對象來表示,值Value能夠使用其他所有對象

對象與數據結構

Redis中存在豐富的對象,常用的對象(數據類型)有字符串對象string、列表對象list、散列對象hash、集合對象set、有序集合對象zset

還有其他的數據類型如Bitmap、Hyperloglog、Geospatial、布隆過濾器等,但這篇文章只涉及常用的對象,其他數據類型再以后的文章中再展開說明

  • redis中的對象RedisObject由類型、編碼、引用次數、lru、指向編碼使用的數據結構對象構成

    • 類型標識這個對象是什么類型對象

      • 比如字符串、列表、哈希、集合、有序集合等
    • 編碼表示構成對應類型對象時使用哪種數據結構

    • 引用次數表示這個對象被引用了多少次

      • redis內存回收使用引用計數法,回收引用次數為0的對象 redis只依賴字符串對象,而不存在循環依賴所以不存在循環引用,因此可以使用引用計數法
    • lru記錄這個對象最近被調用的時間,當空間回收算法使用lru時會優先回收很久未用的對象(后續刪除回收的文章會介紹)

數據結構

sds簡單動態字符串

sds使用字節數組維護,len記錄字符串長度(表示結尾的'\0'不算),free表示字節數組中空閑的長度

image.png

在添加元素前會判斷數組長度是否足夠,不夠則會進行擴容;擴容有空間預分配策略,會留有一部分空閑空間

如果下次修改字符串未超出數組長度就能夠直接修改,節省了擴容的開銷

hashtable字典

字典使用哈希表實現,哈希表的原理本篇文章不會詳細概述

哈希沖突使用鏈地址法解決,查找時先通過 hash%數組長度-1 來獲取索引,得到索引后再遍歷鏈表節點,如果是新增則直接使用頭插法,插入鏈表頭部

image.png

為了防止大字典擴容時發生阻塞,字典中哈希表的擴容是循序漸進的,在發生擴容時會有倆個哈希表

image.png

舊哈希表和新哈希表中都可能存儲數據,再收到hget等請求時先在舊哈希表中查找,找到了就順便把它遷移到新哈希表中;在舊哈希表中沒找到就去新哈希表中找

在完成遷移時,新哈希表將舊哈希表替換

skiplist跳表

跳表維護多層級的有序鏈表,利用高層能夠快速達到后續節點,實現簡單,維護方便,增刪改查時間復雜度平均log n

image.png

比如查找值為2.0的節點,查找順序為圖中虛線

先找到虛擬頭節點,從當前維護的最高層(L5)開始尋找,往后找到o3對象值為3.0,說明已經找過頭了,于是要去下一層進行尋找;來到L4先后遍歷,o1對象值為1.0,比目標值2.0小,說明沒有目標值在o1對象后面,于是來到o1對象L4層;繼續在o1對象L4向后遍歷,發現o3值為3.0大于目標值,于是降層來到o1對象L3層;L3層后面也是o3于是繼續降層,來到L2層,L2層向后遍歷為o2對象,值為2.0并比較o2對象相同說明找到了

從維護的最高層開始查詢,查詢為空或者查詢值大于目標值則降層,當前在最后一層還需要降層說明找不到

當排序值相同時,按照對象大小排序,這里的對象都是字符串對象

增加節點時的層數是隨機生成的,越高層幾率越小;其他修改操作,也是通過查詢再進行,同時還要維護一些如最高層級等其他屬性

intset整數集合

intset 維護了一個有序,無重復的數組

在實現上使用數組、長度(記錄元素數量)和編碼(編碼能夠標識元素類型,如16、32、64位的整型)

image.png

當加入的元素為當前數組內不存在的高位整型時(比如數組中都是32位整型,此時加入一個64位整型)發生升級:先申請內存重分配,再將舊元素移動到對應位置上,然后加入新元素同時修改編碼,當刪除高位整型時不會發生降級

intset的升級有效的節約內存,當set對象都為整型且數據量較小時使用intset實現以此來節約內存

ziplist壓縮列表

ziplist用連續空間的節點構成,節點由記錄前驅節點偏移量(逆序遍歷)、編碼(字節數組或整型的編碼)、內容(內容可以是字節數組或整型)組成

image.png

因為ziplist的內容不是固定的,比如記錄前驅節點偏移量是可變長的,這會影響節點的長度,又因為ziplist是空間連續的,這會導致后續的節點空間都要變動,被稱為連鎖更新(發生的概率小)

為了節省空間,用于數量量小場景下列表、哈希、有序集合的實現

quicklist快速列表

快速列表可以當作雙向鏈表,只不過節點使用ziplist,常用來實現數據量大場景下的列表對象

對象

說明:

下文中數據量代表著占用字節情況和數據元素數量

本篇文章不介紹各個對象的命令使用規則,需要學習命令的同學可以去官網查看

字符串對象

字符串對象string由sds簡單動態字符串來實現

  • sds有不同的編碼:int、embstr、row

    • int 用來存儲整型字符串,計算時可能發生整型與字符串的轉換
    • embstr 用來存儲短的字符串,只分配一次內存,分配內存時同時分配redisobject和sds
    • row 用來存儲長字符串,分配內存時需要分配兩次:redisobject、sds

字符串對象是Redis中最常用的對象,也是唯一會被其他對象依賴使用的對象

字符串對象常見的使用場景:整存整取的緩存、計數器、分布式鎖

列表對象

列表對象list是一個隊列,可以操作隊頭隊尾,由ziplist或quicklist來實現

數據量小時使用ziplist,數據量大時使用quicklist( linkedlist+ziplist )

列表的使用場景是FIFO隊列保證元素訪問順序

哈希對象

哈希對象hash是維護KV鍵值對的無序數據結構,由ziplist或hashtable來實現

數據量少使用ziplist、數據量大使用hashtable

哈希的使用場景是緩存的部分存取(比如一個大禮包下有A商品B商品等)

集合對象

集合對象set的特點是無序、無重,由intset或hashtable來實現

數據量少且數據為整型使用intset、數據量大或數據不為整型使用hashtable且值永遠為null

集合的使用場景是唯一性元素或交集并集(共同關注、可能認識)等(無序、無重復)

有序集合對象

有序集合對象zset是有序、無重的數據結構,由ziplist或skiplist + hashtable實現

數據量少時使用ziplist、數據量大時使用skiplist + hashtable(為了滿足根據對象查詢分指常量級功能,共享對象,不造成內存開銷)

有序集合的使用場景是排行榜、關注程度榜單等(有序、無重復)

總結

本篇文章圍繞Redis以鍵值對存儲、豐富多元的數據結構為特點詳細介紹了Redis中的對象與數據結構

對象由類型、編碼、數據結構指針等構成

為了節省空間,每種類型的對象都有多種編碼類型的數據結構能夠實現

  • 字符串對象常用來做緩存、分布式鎖、計數器等,被其他對象依賴使用

    • 由sds實現主要有int、embstr、row三種編碼來處理不同類型的字符串,embstr處理短字符串優化內存分配
    • sds是動態字符串,利用空間預分配策略在修改不超過數組長度情況下可以不需要進行擴容,節省開銷
  • 列表對象常用來維護隊列元素有序性

    • 當數據量小時使用壓縮列表ziplist實現,數據量大時使用快速列表quicklist實現
    • 壓縮列表使用連續空間,節點中存儲可以時字符串也可以是整型
    • 快速列表則可以當作鏈表,節點為壓縮列表
  • 哈希對象常用來維護部分存取的緩存

    • 當數據量小時使用壓縮列表zpilist實現,數據量大時使用哈希表hashtable實現
    • 哈希表為了防止阻塞,在擴容時使用新舊兩個哈希表存儲元素,在處理命令的同時完成遷移
  • 集合對象有無序、無重的特點,常用來做唯一、交集(共同好友)、并集(可能認識)

    • 當數據量小且元素都為整型時使用整型集合intset實現,當數據量大使用哈希表實現
    • 整型集合有不同的編碼形式,充分節省了空間;使用哈希表時Value為空
  • 有序集合對象有有序、無重的特點,常用來做排行榜

    • 當數據量小時使用壓縮列表實現;當數據量大時使用跳表skiplist+哈希表實現,哈希表保存K對象V比較值
    • 跳表是多層級有序的鏈表,平均時間復雜度在log n,簡單易維護

最后(一鍵三連求求拉~)

本篇文章筆記以及案例被收入 gitee-StudyJava、 github-StudyJava 感興趣的同學可以stat下持續關注喔~

有什么問題可以在評論區交流,如果覺得菜菜寫的不錯,可以點贊、關注、收藏支持一下~

關注菜菜,分享更多干貨,公眾號:菜菜的后端私房菜

本文由博客一文多發平臺 OpenWrite 發布!

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

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

相關文章

運籌學_1.1.4 線性規劃問題-解的概念

1.1.4 線性規劃問題-解的概念 一、可行解與最優解二、基的概念三、基變量、基向量;非基變量、非基向量;基解、基可行解;四、最優解與可行解、基可行解的關系五、用例題(枚舉法)鞏固基解、基可行解、最優解三個概念1、例…

flyway實戰

flyway是一款用來管理數據庫版本的工具框架 一, 添加依賴 <dependency><groupId>org.flywaydb</groupId><artifactId>flyway-core</artifactId> </dependency> <dependency><groupId>org.springframework</groupId>&l…

第十一屆藍橋杯省賽第一場C++ A組 / B組《網絡分析》(c++)

1.題目說明 小明正在做一個網絡實驗。 他設置了 n 臺電腦&#xff0c;稱為節點&#xff0c;用于收發和存儲數據。 初始時&#xff0c;所有節點都是獨立的&#xff0c;不存在任何連接。 小明可以通過網線將兩個節點連接起來&#xff0c;連接后兩個節點就可以互相通信了。 兩…

代碼隨想錄算法訓練營第二十五天 | 216.組合總和III 17.電話號碼的字母組合

216.組合總和III https://programmercarl.com/0216.%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8CIII.html#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%89%88%E6%9C%AC class Solution:def combinationSum3(self, k: int, n: int) -> List[List[int]]:result [] # 存放結果集sel…

實現一個移動端焦點輪播圖

HTML結構&#xff1a; 創建一個輪播圖的容器&#xff0c;并在其中放置輪播圖片。 <div id"carousel"> <div class"carousel-item active"> <img src"image1.jpg" alt"Image 1"> </div> <div class&q…

Docker部署ZooKeeper

在分布式系統中,ZooKeeper是一個關鍵的組件,用于協調和管理多個節點之間的狀態。本文將詳細介紹如何使用Docker安裝和部署ZooKeeper,包括非集群部署和集群部署兩種情況。 非集群部署 前期準備 在開始之前,請確保你已經安裝了Docker,并且擁有sudo權限。 關閉防火墻和SEL…

5、DVWA代碼審計(2)

一、csrf 1、csrf(low) 限制 復現 GET /vulnerabilities/csrf/?password_new123456&password_conf123456&ChangeChange HTTP/1.1 Host: ddd.com Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,…

電子電器架構 —— DoIP協議相關的介紹

電子電器架構 —— DoIP協議相關的介紹 我是穿拖鞋的漢子,魔都中堅持長期主義的汽車電子工程師。 老規矩,分享一段喜歡的文字,避免自己成為高知識低文化的工程師: 沒有人關注你。也無需有人關注你。你必須承認自己的價值,你不能站在他人的角度來反對自己。人生在世,最怕…

監聽者的力量:探索觀察者模式和spring使用

觀察者模式是一種對象行為型設計模式&#xff0c;它定義了對象之間的一對多依賴關系。 觀察者模式通常用于實現分布式事件處理系統、新聞代理或MVC框架的一部分。在這種模式中&#xff0c;一個對象&#xff08;稱為“主題”或“可觀察對象”&#xff09;維護一系列依賴于它的對…

vue3編寫H5適配橫豎屏

具體思路如下&#xff1a; 1、監聽瀏覽器屏幕變化&#xff0c;通過監聽屏幕寬高&#xff0c;辨別出是橫屏&#xff0c;還是豎屏狀態 在項目的起始根頁面進行監聽&#xff0c;我就是在App.vue文件下進行監聽 代碼如下&#xff1a; <template><RouterView /> <…

【Spring IoC】實驗四:特殊值處理

個人名片&#xff1a; &#x1f43c;作者簡介&#xff1a;一名大三在校生&#xff0c;喜歡AI編程&#x1f38b; &#x1f43b;???個人主頁&#x1f947;&#xff1a;落798. &#x1f43c;個人WeChat&#xff1a;hmmwx53 &#x1f54a;?系列專欄&#xff1a;&#x1f5bc;?…

Java4種創建線程方式

目錄 一&#xff1a;繼承Thread 二&#xff1a;重新Runnable接口 三&#xff1a;Callable 四&#xff1a;lambda 一&#xff1a;繼承Thread public static void main(String[] args) {Thread1 t1new Thread1();t1.start(); } class Thread1 extends Thread {Overridepublic…

C++ //練習 10.16 使用lambda編寫你自己版本的biggies。

C Primer&#xff08;第5版&#xff09; 練習 10.16 練習 10.16 使用lambda編寫你自己版本的biggies。 環境&#xff1a;Linux Ubuntu&#xff08;云服務器&#xff09; 工具&#xff1a;vim 代碼塊 /*******************************************************************…

BERTopic安裝最全教程及報錯處理

BERTopic安裝 BERTopic的安裝比較復雜,直接安裝會報錯 安裝方法1,.whl文件安裝 ERROR: Could not build wheels for hdbscan, which is required to install pyproject.toml-based projects正確安裝流程 查看python能安裝whl的版本pip debug --verbose Compatible tags: 2…

圖表背后的智慧:辦公場景中的數據可視化革新

在現代辦公場景中&#xff0c;數據可視化的應用已經成為提高效率、推動創新的得力工具。無論是管理層還是普通員工&#xff0c;都能從數據可視化中受益匪淺。下面我就以可視化從業者的角度&#xff0c;簡單聊聊這個話題。 首先&#xff0c;數據可視化提升了數據的易讀性與理解性…

docker安裝最新版lastest

docker pull mysql 報missing signature key錯誤問題原因&#xff1a;如果安裝docker用的是yum install docker命令的話&#xff0c;下載下來的docker版本為舊版本&#xff0c;所以會有數字簽名有問題 最新版docker安裝方法&#xff1a; 卸載舊版本 Docker&#xff08;如果已安…

【研發日記】Matlab/Simulink技能解鎖(三)——在Stateflow編輯窗口Debug

文章目錄 前言 State斷點 Transition斷點 條件斷點 按State步進 Watch Data Value Sequence Viewer 分析和應用 總結 前言 見《【研發日記】Matlab/Simulink技能解鎖(一)——在Simulink編輯窗口Debug》 見《【研發日記】Matlab/Simulink技能解鎖(二)——在Function編輯…

AQS(抽象隊列同步器)

什么是AQS? AQS&#xff08;AbstractQueuedSynchronizer&#xff09;是Java中用于實現鎖和同步器的基礎框架。它是一個抽象類&#xff0c;提供了一種靈活且強大的方式來實現各種同步器&#xff0c;如ReentrantLock、Semaphore、CountDownLatch等 AQS實現原理&#xff1f; 1、…

Flink狀態存儲-StateBackend

文章目錄 前言一、MemoryStateBackend二、FSStateBackend三、RocksDBStateBackend四、StateBackend配置方式五、狀態持久化六、狀態重分布OperatorState 重分布KeyedState 重分布 七、狀態過期 前言 Flink是一個流處理框架&#xff0c;它需要對數據流進行狀態管理以支持復雜的…

10個技巧,3分鐘教會你高效尋找開源項目

作為程序員&#xff0c;不論是開發還是學習&#xff0c;肯定會用到開源項目&#xff0c;那么怎么快速在開源網站找到這些項目呢&#xff1f; 常用的開源網站有&#xff1a;github 和 gitee github是全球最大的開源社區&#xff0c;今天就以github為例&#xff0c;演示一下 gi…