秋招Day14 - Redis - 底層結構

Redis都有哪些底層數據結構?

有八種核心的底層數據結構。

SDS

Redis自己實現的動態字符串,SDS結構中直接存儲了已使用的字符數組長度len和未使用的字符數組長度free,所以獲取長度的時間復雜度是O(1),還支持動態擴容,以及存儲二進制數據

字典

數組+鏈表實現的哈希表,為了避免rehash時一次性移動大量數據,底層使用了兩個哈希表,后續的每次訪問都會將將舊哈希表中的一部分數據移動到新的擴容后的哈希表,叫做漸進式rehash

ziplist?

節省內存的緊湊型數據結構,所有的元素連續存儲在一塊內存里,但它有個致命的問題,叫做“連鎖更新”,因為ziplist節點中記錄的是上一個節點的總長度,所以上一個節點的總長度變化跨越了某個臨界值(比如previous_entry_length 字段從1字節擴展為5字節)可能使其后面的所有元素內部都要重新編碼,性能急劇下降。?

quicklist

為了解決壓縮列表的問題,Redis 后來設計了 quicklist。這個設計思路很聰明,它把 ziplist 拆分成小塊,然后用雙向鏈表把這些小塊串起來。這樣既保持了 ziplist 節省內存的優勢,又避免了連鎖更新的問題,因為每個小塊的 ziplist 都不會太大。

listpack

為了解決ziplist的連鎖更新問題,listpack中每個節點只記錄自己的長度而不記錄上一個節點的長度,前面節點的總長度變化不會觸發后面節點的長度發生變化,不會引發連鎖反應

skiplist

跳表skiplist主要存在于有序集合ZSet中,通過多層指針實現快速查找,平均時間復雜度是O(logn),支持范圍查詢

intset?

整數集合,當Set中都是整數且數量較少時使用,內部是一個有序數組,查找時使用二分法。?

LinkedList

早期版本使用,后來被quicklist取代,因為內存不連續,影響CPU緩存性能

簡單介紹下鏈表?

Redis的LinkedList是一個雙向無環結構,類似于java的LinkedList。

節點由 listNode 表示,每個節點都有指向其前置節點和后置節點的指針,頭節點的前置和尾節點的后置均指向 null。

關于整數集合再詳細說說

整數集合是 Redis 中一個非常精巧的數據結構,當一個 Set 只包含整數元素,并且數量不多時,默認不超過 512 個,Redis 就會用 intset 來存儲這些數據。

有三種編碼方式,16位、32位、64位,有類型升級機制,會根據存儲的整數大小動態調整編碼。比如原來存的都是小整數,用 16 位編碼就夠了,但突然插入了一個很大的數,超出了 16 位的范圍,這時整個數組會升級到 32 位編碼。

當然了,這種升級是有代價的,因為需要重新分配內存并復制數據,并且是不可逆的,但它的好處是可以節省內存空間,特別是在存儲大量小整數時。

另外,所有元素在數組中按照從小到大的順序排列,這樣就可以使用二分查找來定位元素,時間復雜度為?O(log N)

說一下ZSet的底層原理?

有兩種底層實現機制:壓縮列表跳表

壓縮列表

存儲的元素數量少于128個,每個元素的大小小于64字節的時候,使用壓縮列表。

使用壓縮列表時,每個元素會使用兩個列表中的節點表示,前一個存儲元素值,后一個存儲score

所有元素按分值從小到大有序排列,小的放在靠近表頭的位置,大的放在靠近表尾的位置。

skiplist

元素數量較多或元素本身較大時,會采用skiplist的編碼方式,這個設計同時使用了兩種數據結構:跳表字典(哈希表)。

跳表按分數排序所有元素,通過多層鏈表實現,支持范圍查詢,平均時間復雜度為?O(log N)。而哈希表則用來存儲成員和分值的映射關系,查找時間復雜度為?O(1)

雖然同時使用兩種結構,但它們會通過指針來共享相同元素的成員和分值,因此不會浪費額外的內存。

為什么Redis7.0要用listpack代替ziplist?

主要是為了解決壓縮列表的一個核心問題——連鎖更新。在壓縮列表中,每個節點都需要記錄前一個節點的長度信息

當插入或刪除一個節點時,如果這個操作導致某個節點的長度發生了變化,那么后續的節點可能都需要更新它們存儲的"前一個節點長度"字段。如果前一個節點過長甚至可能會擴展字段的位數。

而 listpack 的設計理念完全不同。它讓每個節點只記錄自己的長度信息,不再依賴前一個節點的長度。這樣就從根本上避免了連鎖更新的問題。

連鎖更新是怎么發生的?

比如說我們有一個壓縮列表,其中有幾個節點的長度都是 253 個字節。在 ziplist 的編碼中,如果前一個節點的長度小于 254 字節,我們只需要 1 個字節來存儲這個長度信息。

但如果在這些節點前面插入一個長度為 254 字節的節點,那么原來只需要 1 個字節存儲長度的節點現在需要 5 個字節來存儲長度信息。這就會導致后續所有節點的長度信息都需要更新,因為大家的長度都是253。

研究過Redis字典源碼嗎?

有,Redis字典分為三層,最外層是一個dict結構,包含兩個哈希表ht[0]和ht[1],然后是哈希表結構dictht,每個dictht里有一個dictEntry,是數組+鏈表的結構。

字典最大的特點是漸進式rehash,擴容時的數據重新分布不是一次性完成的,而是隨著舊字典中數據的訪問而分批復制移動。

當舊哈希表的元素數量達到閾值的時候,Redis會為ht[1]分配新的空間,通常是ht[0]的兩倍,然后將ht[0]中的中的rehashidx設置為0,代表正在進行rehash的桶索引。

接下來每次操作舊字典的時候,都會將rehashidx指向的桶中的所有鍵值對從ht[0]復制移動到ht[1]中,然后rehashidx遞增,直到整個ht[0]遷移完畢,此時會交換h[0]和h[1]的角色。

rehash期間查找的時候會先在h[0]中查找,如果沒有找到再從h[1]中查找,新元素則直接插入h[1]

遇到哈希沖突怎么辦??

通過鏈地址法解決,哈希表中的每個槽位是一個鏈表的頭指針,當多個鍵的哈希值映射到同一個槽位時,這些鍵會以鏈表的形式利用頭插法串聯起來。

你了解跳表嗎?

跳表是一種非常巧妙的數據結構,它在有序鏈表的基礎上建立了多層索引,最底層包含所有數據,每往上一層,節點數量就減少一半。

它的核心思想是"用空間換時間",通過多層索引來跳過大量節點不斷縮小范圍,從而提高查找效率。

怎么往跳表中插入節點呢?

從頂層開始,在每層向右移動直到下個節點的值大于要插入的值,用一個 update 數組記錄每一層應該插入的位置的前驅節點,然后下降到下一層。

插入到最底層后,接下來隨機生成新節點的層數。通常用一個循環,每次有 50% 的概率繼續往上,直到隨機失敗或達到最大層數限制。利用之前記錄的 update 數組,將新節點插入到正確位置,然后更新前后指針的連接關系

zset為什么要使用跳表?

第一,跳表天然就是有序的數據結構,查找、插入和刪除都能保持?O(log n)?的時間復雜度。

第二,跳表支持范圍查詢找到起始位置后可以直接沿著底層鏈表順序遍歷,滿足 ZRANGE 按排名獲取元素,或者 ZRANGEBYSCORE 按分值范圍獲取元素。

跳表是如何定義的?

本質上是一個多層鏈表最底層是一個包含所有元素的有序鏈表,之上的每一層作為索引鏈表,包含了下一層的部分節點,層數通過隨機算法確定,理論上可以無限高。

跳表節點skiplistNode包含分值score、成員對象obj、一個后退指針backward,以及一個層級數組level。每個層級數組里有前進指針forward和跨度信息(到下一個節點的距離)span

跳表本身包含頭尾節點,節點總數length和當前最大層級level

跨度信息span有什么用??

span 記錄的是當前節點?forward 指針所跨越的底層節點的數量,從頂層的rank = 0開始,通過累加搜索過程中的span,快速找到ZSet中某個分值的排名,而無需遍歷底層數組。

壓縮列表了解嗎?

壓縮列表是 Redis 為了節省內存而設計的一種緊湊型數據結構,它會把所有數據連續存儲在一塊內存當中。

ziplist的頭部信息包含總字節數zlbytes、最后一個節點的偏移量zltail、總節點數量zllen、實際數據區域entryX。

當 list、hash 和 set 的數據量較小且值都不大時,底層會使用壓縮列表來實現。

通常情況在,每個節點包含三個部分:前一個節點的長度編碼類型實際的數據

前一個節點的長度是為了支持從后往前遍歷;當前一個節點的長度小于 254 字節時,使用 1 字節存儲;否則用 5 字節存儲,第一個字節設置為 254,后四個字節存儲實際長度。

但壓縮列表有個致命問題,就是連鎖更新。當插入或刪除節點導致某個節點長度發生變化時,可能會影響后續所有節點存儲的“前一個節點長度”字段,最壞情況下時間復雜度會退化到?O(n2)

ziplist的節點數量會大于65535嗎?

不會。

Zllen 字段的類型是?uint16_t最大值為 65535,也就是 2 的 16次方,所以壓縮列表的節點數量不會超過 65535。

當節點數量小于 65535 時,該字段會存儲實際的數量;否則該字段就固定為 65535,實際存儲的數量需要逐個遍歷節點來計算。

ziplist的編碼類型了解多少?

ziplist每個節點的編碼類型都可以不同,主要分為字符串編碼整數編碼兩大類,目的是用最少的字節存儲數據。

編碼長度描述
110000001字節int16_t類型整數,2 字節
110100001字節int32_t類型整數,4 字節
111000001字節int64_t類型整數,8 字節
111100001字節24位有符號整數 ,3 字節
1111xxxx1字節數據范圍在[0-12],數據包含在編碼中
編碼長度描述
00pppppp1字節0-63 字節的字符串
01pppppp qqqqqqqq2字節64-16383字節的字符串
10______ qqqqqqqq rrrrrrrr ssssssss tttttttt5字節16384-4294967295字節的字符串

quicklist了解嗎?

結合了壓縮列表雙向鏈表的優點,quicklist 通過將 List 拆分為多個小的 ziplist,再通過指針鏈接成一個雙向鏈表,巧妙的解決了連鎖更新問題。這樣既保留了壓縮列表的內存緊湊性,又減少了雙向鏈表指針的數量,進一步降低了內存開銷。

quicklist每個節點的元素數量或大小是可配置的,默認每個節點是8KB的大小。

如果想進一步節省內存,quicklist支持對中間節點進行LZF壓縮

LZF壓縮了解嗎?

是一種無損壓縮算法,用來減少數據占用的內存,核心思想是通過查找重復元素來實現壓縮,通過一個滑動窗口來查找重復的字節序列,將這些序列替換為更短的引用

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

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

相關文章

使用Mac自帶的圖像捕捉導出 iPhone 相冊

用 數據線 將 iPhone 連接到 Mac必須是數據線,有些充電線插上去后無法識別到iphone在 iPhone 上點擊“信任此電腦”在 Mac 上打開應用:快速方式:按 Command Space 打開 Spotlight,輸入 圖像捕捉 或 Image Capture,回車或者從 /系…

【UniApp picker-view 多列對齊問題深度剖析與完美解決】

UniApp picker-view 多列對齊問題深度剖析與完美解決一次看似簡單的樣式調整,卻引發了對構建工具、CSS 預處理和組件渲染機制的深度思考創作時間: 2025/7/1 技術棧: UniApp Vue3 TypeScript PostCSS 問題級別: 🔴 高級🎯 問題背景 在開發 …

R Studio開發中記錄

1.如何將tar.gz格式的源碼R包編譯為zip格式的二進制R包。 R CMD INSTALL --build knhanes.tar.gz R CMD INSTALL --build nhanes.tar.gz 2.下載RTools RTools: Toolchains for building R and R packages from source on Windows 3.修改環境變量 PATH$PATH:/d/rtools45/usr…

量化交易中的隱藏模式識別:基于潛在高斯混合模型的機會挖掘

*——從市場噪聲中提取黃金信號的數學藝術** > 2025年3月,某對沖基金使用潛在高斯混合模型捕捉到銅期貨的異常波動模式,提前布局實現單月收益47%。核心代碼僅20行,卻顛覆了傳統技術分析范式。 --- ### 01 市場迷思:為何90%的交易者失敗? 金融市場本質是**非…

Qt窗口被外部(非Qt內部機制)強制銷毀,第二次再重復使用不顯示

在Qt開發中,窗口被外部(非Qt內部機制)強制銷毀 警告信息 External WM_DESTROY received for QWidgetWindow(0x108b8cbdb10, name"xxxxx") , parent: QWindow(0x0) , transient parent: QWindow(0x0) 使用場景 代碼結構如下&#x…

一文詳解Character AI:實用指南+ ChatGPT、Gemini對比分析

本指南將深入剖析Character AI的運行機制、功能特性及其存在的局限性。 近年來,生成式人工智能領域發展態勢迅猛,其應用范疇已遠超單純的文本生成領域。在眾多備受矚目的新興平臺中,Character AI是一款支持用戶以對話形式與人工智能生成角色…

遺傳算法的原理與實現示例

遺傳算法是一種受生物進化理論啟發的隨機優化算法,其核心思想是模擬自然界中 “物競天擇、適者生存” 的進化過程,通過對候選解的迭代優化,找到問題的最優解。 一、核心思想 遺傳算法將優化問題的候選解視為生物群體中的“個體”&#xff0c…

centos7 ping127.0.0.1不通

ping 127.0.0.1,localhost和本地ip都不通,所有的配置也是正確的 檢查下是否禁止了ping vim /proc/sys/net/ipv4/icmp_echo_ignore_all 內容為 1 禁止ping 內容為0 開啟ping sysctl -w net.ipv4.icmp_echo_ignore_all0 變更以上設置即可

【無標題】JavaScript入門

JS 1.JS引入方式 <!DOCTYPE html><html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>JS-引入方式</title><!-- …

(JAVA)自建應用調用企業微信API接口,實現消息推送

建議先簡單了解企業微信開發者中心文檔&#xff1a;開發前必讀 - 文檔 - 企業微信開發者中心 了解一下企業微信調用接口的基礎參數&#xff1a;基本概念介紹 - 文檔 - 企業微信開發者中心 本篇每個步驟都會跟著官網文檔走&#xff0c;都會貼上相關鏈接&#xff0c;看完本篇文…

P/Invoke 在默認封送(marshalling)規則下,常見托管 ? 非托管類型的對應關系

下表整理了 P/Invoke 在默認封送&#xff08;marshalling&#xff09;規則下&#xff0c;常見托管???非托管類型的對應關系。 內容主要依據微軟官方 Marshalling Data with?Platform?Invoke 文檔&#xff0c;并補充了常見指針&#xff0f;句柄用法與字符串緩沖區&#xff…

2.isaacsim4.2 教程-初識OmniGraph

1. OmniGraph&#xff08;視覺編程&#xff09; OmniGraph 是 Omniverse 的可視化編程框架。它提供了一個圖狀結構&#xff0c;將 Omniverse 內多個系統的功能節點串聯起來&#xff1b;同時也是一個計算框架&#xff0c;允許你編寫高度自定義的節點&#xff0c;將自己的功能無…

MonoGame 游戲開發框架日記 -03

第三章&#xff1a;創建類庫 內容介紹 主要內容&#xff1a;創建Core類并編寫 創建這個類主要是為了后續開發方便&#xff0c;并介紹游戲開發中的一種非常重要編程模式 單例模式&#xff0c;以及了解MonoGame基本圖形渲染知識單例模式&#xff1a; 第一步我們得先了解什么是單例…

AES 256 CBC加密和解密

AES-256-CBC 是一種對稱加密算法&#xff0c;使用 256位密鑰 和 CBC&#xff08;Cipher Block Chaining&#xff09;模式。它的典型使用場景包括對敏感信息進行加密存儲或傳輸。下面是 AES-256-CBC 的加密與解密的 Python 示例&#xff0c;使用 pycryptodome 庫&#xff1a; &a…

Git 版本控制完全指南:從入門到精通

Git 版本控制完全指南&#xff1a;從入門到精通 作為當今最流行的分布式版本控制系統&#xff0c;Git 已經成為開發者必備的技能之一。無論你是獨立開發者還是團隊協作&#xff0c;Git 都能幫助你高效管理代碼版本。本文將帶你從零開始&#xff0c;逐步掌握 Git 的核心概念和常…

408第三季part2 - 計算機網絡 - 計算機網絡分層結構

理解 PCI會放一些控制信息&#xff0c;源地址目的地址都在里面 SDU是放的數據 整個加起來是PDU 每一層的SDU都是上一層的PDU 看一看 也是簡單看一看就行 網絡層有時候也叫IP數據報 這里斷點下載的意思就是&#xff0c;你下載東西的時候網絡斷了&#xff0c;再連回來的時候會接…

打開攝像頭,服務器和客戶端傳輸攝像頭圖像數據

1&#xff1a;Camera Server 主要功能&#xff0c;打開攝像頭&#xff0c;接收客戶端請求 接收到客戶端請求“R”字符后開始傳輸攝像頭圖像。 #include "mainwindow.h" #include "ui_mainwindow.h"#include<QDebug>MainWindow::MainWindow(QWidget…

Android實現獲取前臺應用信息

Android實現獲取前臺應用信息 1.前言&#xff1a; 之前需要獲取在后臺運行的App信息&#xff0c;比如包名、版本這些常規的&#xff0c;今天是講解獲取在前臺的App信息&#xff0c;雖然App在前臺&#xff0c;但是具體的信息可能不知道&#xff0c;今天就嘗試獲取一下&#xf…

快訊|美團即時零售日訂單已突破1.2億,餐飲訂單占比過億

據美團內網公布信息顯示&#xff0c;截至22時54分&#xff0c;美團即時零售當日訂單已經突破了1.2億單&#xff0c;其中&#xff0c;餐飲訂單已超過1億單。 值得注意的是&#xff0c;就在當晚20時45分&#xff0c;美團內網曾顯示即時零售日訂單突破了1億。這也意味著&#xff…

pycharm2018配置gitee操作

一、gitee介紹及下載安裝 gitee介紹&#xff1a; gitee別名碼云&#xff0c;是中國的一個代碼托管平臺&#xff0c;類似于GitHub&#xff0c;基于Git技術&#xff0c;提供遠程倉庫托管、協作功能和開源社區服務&#xff0c;優勢包括訪問速度快、本地化服務和政策合規git和gite…