搜尋
首頁資料庫Redis詳解Redis中的資料結構

詳解Redis中的資料結構

Mar 31, 2021 am 10:26 AM
javaredis場景應用資料結構面試

詳解Redis中的資料結構

在實際開發,Redis使用會頻繁,那麼在使用過程中我們該如何正確抉擇資料型別呢?哪些場景下適用哪些資料類型。而且在面試中也很常被面試官問到Redis資料結構方面的問題:

  • Redis為什麼快呢?
  • 為什麼查詢操作會變慢了?
  • Redis Hash rehash過程
  • 為什麼使用哈希表作為Redis的索引

當我們分析了解Redis資料結構,可以為了我們在使用Redis的時候,正確抉擇資料型別使用,提升系統效能。 【相關推薦:Redis影片教學

Redis底層資料結構

Redis 是一個記憶體鍵值key-value 資料庫,且鍵值對資料保存在記憶體中,因此Redis基於記憶體的資料操作,其效率高,速度快;

其中,KeyString類型,Redis 支援的value 類型包括了StringListHashSetSorted SetBitMap等。 Redis 能夠之所以能夠廣泛地適用眾多的業務場景,基於其多樣化類型的value

RedisValue的資料型別是基於為Redis自訂的物件系統redisObject實現的,

typedef struct redisObject{
    //类型
    unsigned type:4;
    //编码
    unsigned encoding:4;
    //指向底层实现数据结构的指针
    void *ptr;
    ….. 
}

redisObject除了記錄實際數據,還需要額外的內存空間記錄數據長度、空間使用等元數據信息,其中包含了8 字節的元數據和一個8 位元組指針,指針指向具體資料型別的實際資料所在位置:

詳解Redis中的資料結構

#其中,指標指向的就是基於 Redis的底層資料結構儲存資料的位置,Redis的底層資料結構:SDS,雙向鍊錶、跳表,雜湊表,壓縮列表、整數集合實現的。

那麼Redis底層資料結構是怎麼實現的呢?

Redis底層資料結構實作

我們先來看看Redis比較簡​​單的SDS,雙向鍊錶,整數集合

SDS、雙向鍊錶和整數集合

SDS,使用len欄位記錄已使用的位元組數,將取得字串長度複雜度降低為O(1),而且SDS惰性釋放空間的,你free了空間,系統把資料記錄下來下次想用時候可直接使用。不用新申請空間。
詳解Redis中的資料結構
整數集合,在記憶體中分配一塊位址連續的空間,資料元素會挨著存放,不需要額外指標帶來空間開銷,其特點為記憶體緊湊節省記憶體空間,查詢複雜度為O(1)效率高,其他操作複雜度為O(N);

雙向鍊錶 , 在記憶體上可以為非連續、非順序空間,透過額外的指標開銷前驅/後驅指標串聯元素之間的順序。

其特性為節插入/更新資料複雜度為O(1)效率高,查詢複雜度為O(N);

Hash哈希表

哈希表,其實類似是數組,數組的每個元素稱為一個哈希桶,每個哈希桶中保存了鍵值對數據,且哈希桶中的元素使用dictEntry結構,
詳解Redis中的資料結構

#因此,雜湊桶元素保存的並不是鍵值對值本身,而是指向具體值的指針,所以在儲存每個鍵值對的時候會額外空間開銷,至少有增加24個字節,特別是ValueString的鍵值對,每一個鍵值對就需要額外開銷24個位元組空間。當保存資料小,額外開銷比資料還大時,這時為了節省空間,考慮換資料結構。

那來看看全域雜湊表全圖:
詳解Redis中的資料結構
雖然雜湊表操作很快,但Redis資料變大後,就會出現一個潛在的風險:哈希表的衝突問題和rehash開銷問題這可以解釋為什麼哈希表操作變慢了?

當到哈希表中寫入更多資料時,哈希衝突是不可避免的問題, Redis 解決哈希衝突的方式,就是鍊式哈希 ,同一個哈希桶中的多個元素用一個鍊錶來保存,它們之間依次用指針連接,如圖所示:
詳解Redis中的資料結構

當哈希衝突也會越來越多,這就會導致某些哈希衝突鏈過長,進而導致這個鏈上的元素查找耗時長,效率降低。
  • 為了解決哈希衝突帶了的鏈過長的問題,進行
  • rehash
  • 操作
  • ,增加現有的哈希桶數量,分散單桶元素數量。那麼
rehash

過程怎麼樣執行的呢?

Rehash為了使#rehash 操作更有效率,使用兩個全域哈希表:哈希表1和哈希表2,具體如下:

將哈希表2 分配更大的空間,

把哈希表1 中的資料重新映射並拷貝到哈希表2 中;

詳解Redis中的資料結構釋放哈希表1 的空間

但由於表1和表2在重新映射複製時資料大,如果一次把哈希表1 中的資料都遷移完,會造成Redis

執行緒阻塞,無法服務其他請求。

為了避免這個問題,保證Redi

s能正常處理客戶端請求,

Redis 採用了漸進式
rehash詳解Redis中的資料結構

每處理一個請求時,從哈希表1 中依次將索引位置上的所有entries 拷貝到哈希表2 中,把一次性大量拷貝的開銷,分攤到了多次處理請求的過程中,避免了耗時操作,並保證了資料的快速存取。

在理解完Hash雜湊表相關知識點後,看看不常見的壓縮清單和跳表。

壓縮清單與跳表

詳解Redis中的資料結構

壓縮清單

,在陣列基礎上,在壓縮清單在表頭有三個欄位zlbytes、zltail 和zllen,分別表示列表長度、列表尾的偏移量和列表中的entry 個數;壓縮列表在表尾還有一個zlend,表示列表結束。

記憶體緊湊節省記憶體空間,記憶體中分配一塊位址連續的空間,資料元素會挨著存放,不需要額外指標帶來空間開銷;找出定位第一個元素和最後一個元素,可以透過表頭三個欄位的長度直接定位,複雜度是O(1)。 跳表 ,在鍊錶的基礎上,增加了多層索引,透過索引位置的幾個跳轉,實現資料的快速定位,如下圖所示: 特點:當資料量很大時,跳表的查找複雜度為O(logN)。 綜上所述,可以得知底層資料結構的時間複雜度:##時間複雜度雜湊表O(1)整數陣列 O(N)
優點:
例如查詢33
資料結構類型
###雙向鍊錶######O(N)############壓縮清單######O( N)############跳表######O(logN)#############

Redis自訂的物件系統類型即為RedisValue的資料類型,Redis的資料類型是基於底層資料結構實現的,那資料型態有哪些呢?

Redis資料類型

StringListHashSorted Set Set比較常見的類型,其與底層資料結構對應關係如下:

資料類型 #資料結構
String SDS(簡單動態字串)
List #雙向鍊錶
壓縮清單
Hash 壓縮清單
雜湊表
Sorted Set 壓縮清單
跳表
#Set 哈希表
整數陣列

資料型態對應特性跟其實現的底層資料結構差不多,性質也是一樣的,且

String,基於SDS實現,適用於簡單key-value儲存、setnx key value實作分散式鎖定、計數器(原子性)、分散式全域唯一ID。

List, 按照元素進入List 的順序進行排序的,遵循FIFO(先進先出)規則,一般使用在 排序統計以及簡單的訊息佇列。

Hash, 是字串key和字串value之間的映射,十分適合用來表示一個物件訊息,特點添加和刪除操作複雜度都是O(1)。

Set,是String 類型元素的無序集合,集合成員是唯一的,這表示集合中不能出現重複的資料。基於哈希表實現的,所以添加,刪除,查找的複雜度都是 O(1)。

Sorted Set,  是Set的類型的升級, 不同的是每個元素都會關聯一個 double 類型的分數,透過分數排序,可以範圍查詢。

那我們再來看看這些資料類型,Redis GeoHyperLogLogBitMap

Redis Geo, 將地球看為近似為球體,基於GeoHash 將二維的經緯度轉換成字串,來實現位置的分割跟指定距離的查詢。特點一般使用在跟位置有關的應用。

HyperLogLog, 是一種機率資料結構,它使用機率演算法來統計集合的近似基數 , 錯誤率大概在0.81%。當集合元素數量非常多時,它計算基數所需的空間總是固定的,而且還很小,適合使用做 UV 統計。

BitMap ,用一個位元位元來映射某個元素的狀態, 只有0 和1 兩種狀態,非常典型的二值狀態,且其本身是用String 類型作為底層資料結構實現的一種統計二值狀態的資料類型 ,優勢大量節省記憶體空間,可是使用在二值統計場景。

在理解上述知識後,我們接下來討論一下根據哪些策略選擇相對應的應用場景下的Redis資料類型?

選擇適合的Redis資料類型策略

#在實際開發應用程式中,Redis可以適用於眾多的業務場景,但我們需要怎麼選擇資料類型儲存呢?

主要依據就是時間/空間複雜度,在實際的開發中可以考慮以下幾個點:

  • 資料量,資料本身大小
  • 集合類型統計模式
  • 支援單點查詢/範圍查詢
  • 特殊使用場景

#資料量,資料本身大小

#當資料量比較大,資料本身比較小,使用String就會使用額外的空間大大增加,因為使用雜湊表儲存鍵值對,使用dictEntry 結構保存,會導致保存每個鍵值對時額外保存dictEntry的三個指標的開銷,這樣就會導致資料本身小於額外空間開銷,最終會導致儲存空間資料大小遠大於原本資料儲存大小。

可以使用基於整數陣列壓縮列表實作了ListHashSorted Set ,因為整數數組壓縮列表在記憶體中都是分配一塊位址連續的空間,然後把集合中的元素一個接一個地放在這塊空間內,非常緊湊,不用再透過額外的指針把元素串接起來,這就避免了額外指針帶來的空間開銷。而且採用集合類型時,一個 key 就對應一個集合的數據,能保存的數據多了很多,但也只用了一個 dictEntry,這樣就節省了記憶體。

集合類型統計模式

Redis集合類型統計模式常見的有:

  • 聚合統計( 交集、差集、並集統計):  對多個集合進行聚合計算時,可以選擇Set;
  • 排序統計(要求集合類型能對元素保序): RedisListSorted Set是有序集合,List是依照元素進入 List 的順序進行排序的,Sorted Set 可以依照元素的權重來排序;
  • 二值狀態統計( 集合元素的取值就只有0 和1 兩種) :Bitmap 本身是用String 類型作為底層資料結構實現的一種統計二值狀態的資料類型, Bitmap透過BITOP 按位元與、或、異或的操作後使用BITCOUNT 統計1 的個數。
  • 基數統計(統計一個集合中不重複的元素的個數):HyperLogLogLog 是一種用於統計基數的資料集合類型,統計結果是有一定誤差的,標準誤算率是0.81% 。需要精確統計結果的話,用 Set 或 Hash 類型。

詳解Redis中的資料結構

Set類型,適用統計使用者/好友/追蹤/粉絲/有興趣的人集合聚合操作,例如

  • 統計手機APP每天的新增用戶數
  • 兩個用戶的共同好友

#RedisList#和Sorted Set是有序集合,使用應對集合元素排序需求,例如

  • #最新評論清單
  • 排行榜

#Bitmap二值狀態統計,適用資料量大,且可以使用二值狀態表示的統計,例如:

  • 簽到打卡,當天使用者簽到數字
  • 使用者週活躍
  • 使用者線上狀態

HyperLogLogLog 是一種用於統計基數的資料集合類型,統計一個集合中不重複的元素個數,例如

  • 統計網頁的UV , 一個使用者一天內的多次造訪只能算一次

支援單點查詢/範圍查詢

RedisListSorted Set是有序集合支援範圍查詢,但是Hash是不支援範圍查詢的

特殊使用場景

訊息佇列,使用Redis作為訊息佇列的實現,要訊息的基本要求訊息保序處理重複的訊息保證訊息可靠性,方案有如下:

  • 基於List 的訊息佇列解決方案
  • 基於Streams 的訊息佇列解決方案

基於List 基於Strems
訊息保序 使用LPUSH/RPOP 使用XADD/XREAD
阻塞讀取 #使用BRPOP 使用XREAD block
重複訊息處理 #生產者自行實作全域唯一ID Streams自動產生全域唯一ID
訊息可靠性 使用BRPOPLPUSH 使用PENDING List自動留存訊息

適用場景訊息總量小

訊息總量大,需要消費群組形式讀取資料

#########基於位置LBS 服務###,使用###Redis###的特定###GEO###資料類型實現,###GEO### 可以記錄經緯度形式的地理位置信息,被廣泛地應用在LBS 服務中。 例如:叫車軟體是怎麼基於位置提供服務的。 #########總結############Redis###之所以那麼快,是因為其基於記憶體的資料運算和使用###Hash###哈希表格作為索引,其效率高,速度快,而且得益於其底層資料多樣化使得其可以適用於眾多場景,不同場景中選擇合適的資料類型可以提升其查詢效能。 ######更多程式相關知識,請造訪:###程式設計影片###! ! ###

以上是詳解Redis中的資料結構的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:segmentfault。如有侵權,請聯絡admin@php.cn刪除
REDIS:它如何充當數據存儲和服務REDIS:它如何充當數據存儲和服務Apr 24, 2025 am 12:08 AM

REDISACTSASBOTHADATASTOREANDASERVICE.1)ASADATASTORE,ITUSESIN-MEMORYSTOOGATOFORFOFFASTESITION,支持VariousDatharptructuresLikeKey-valuepairsandsortedsetsetsetsetsetsetsets.2)asaservice,ItprovidespunctionslikeItionitionslikepunikeLikePublikePublikePlikePlikePlikeAndluikeAndluAascriptingiationsmpleplepleclexplectiations

REDIS與其他數據庫:比較分析REDIS與其他數據庫:比較分析Apr 23, 2025 am 12:16 AM

Redis與其他數據庫相比,具有以下獨特優勢:1)速度極快,讀寫操作通常在微秒級別;2)支持豐富的數據結構和操作;3)靈活的使用場景,如緩存、計數器和發布訂閱。選擇Redis還是其他數據庫需根據具體需求和場景,Redis在高性能、低延遲應用中表現出色。

REDIS的角色:探索數據存儲和管理功能REDIS的角色:探索數據存儲和管理功能Apr 22, 2025 am 12:10 AM

Redis在數據存儲和管理中扮演著關鍵角色,通過其多種數據結構和持久化機製成為現代應用的核心。 1)Redis支持字符串、列表、集合、有序集合和哈希表等數據結構,適用於緩存和復雜業務邏輯。 2)通過RDB和AOF兩種持久化方式,Redis確保數據的可靠存儲和快速恢復。

REDIS:了解NOSQL概念REDIS:了解NOSQL概念Apr 21, 2025 am 12:04 AM

Redis是一種NoSQL數據庫,適用於大規模數據的高效存儲和訪問。 1.Redis是開源的內存數據結構存儲系統,支持多種數據結構。 2.它提供極快的讀寫速度,適合緩存、會話管理等。 3.Redis支持持久化,通過RDB和AOF方式確保數據安全。 4.使用示例包括基本的鍵值對操作和高級的集合去重功能。 5.常見錯誤包括連接問題、數據類型不匹配和內存溢出,需注意調試。 6.性能優化建議包括選擇合適的數據結構和設置內存淘汰策略。

REDIS:現實世界的用例和示例REDIS:現實世界的用例和示例Apr 20, 2025 am 12:06 AM

Redis在現實世界中的應用包括:1.作為緩存系統加速數據庫查詢,2.存儲Web應用的會話數據,3.實現實時排行榜,4.作為消息隊列簡化消息傳遞。 Redis的多功能性和高性能使其在這些場景中大放異彩。

REDIS:探索其功能和功能REDIS:探索其功能和功能Apr 19, 2025 am 12:04 AM

Redis脫穎而出是因為其高速、多功能性和豐富的數據結構。 1)Redis支持字符串、列表、集合、散列和有序集合等數據結構。 2)它通過內存存儲數據,支持RDB和AOF持久化。 3)從Redis6.0開始引入多線程處理I/O操作,提升了高並發場景下的性能。

Redis是SQL還是NOSQL數據庫?答案解釋了Redis是SQL還是NOSQL數據庫?答案解釋了Apr 18, 2025 am 12:11 AM

RedisisclassifiedasaNoSQLdatabasebecauseitusesakey-valuedatamodelinsteadofthetraditionalrelationaldatabasemodel.Itoffersspeedandflexibility,makingitidealforreal-timeapplicationsandcaching,butitmaynotbesuitableforscenariosrequiringstrictdataintegrityo

REDIS:提高應用程序性能和可擴展性REDIS:提高應用程序性能和可擴展性Apr 17, 2025 am 12:16 AM

Redis通過緩存數據、實現分佈式鎖和數據持久化來提升應用性能和可擴展性。 1)緩存數據:使用Redis緩存頻繁訪問的數據,提高數據訪問速度。 2)分佈式鎖:利用Redis實現分佈式鎖,確保在分佈式環境中操作的安全性。 3)數據持久化:通過RDB和AOF機制保證數據安全性,防止數據丟失。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。