目錄
整數集合
首頁 資料庫 Redis Redis的基礎資料結構是怎麼樣的

Redis的基礎資料結構是怎麼樣的

May 27, 2023 pm 04:02 PM
redis

整數集合

如果一個集合只包含不多的整數元素,那麼Redis會使用整數集合intset。首先來看 intset 的資料結構:

typedef struct intset {
    // 编码方式
    uint32_t encoding;
    // 集合包含的元素数量
    uint32_t length;
    // 保存元素的数组
    int8_t contents[];
} intset;
登入後複製

其實 intset 的資料結構比較好理解。一個資料保存元素,length 保存元素的數量,也就是contents的大小,encoding 用來保存資料的編碼方式。

透過程式碼我們可以知道,encoding 的編碼型別包含了:

#define INTSET_ENC_INT16 (sizeof(int16_t))
#define INTSET_ENC_INT32 (sizeof(int32_t))
#define INTSET_ENC_INT64 (sizeof(int64_t))
登入後複製

其實我們可以看出來。 Redis encoding的類型,就是指資料的大小。作為一個記憶體資料庫,採用這種設計就是為了節約記憶體。

既然有從小到大的三個資料結構,在插入資料的時候盡可能使用小的資料結構來節約內存,如果插入的資料大於原有的資料結構,就會觸發擴容。

擴充有三個步驟:

  1. 根據新元素的類型,修改整個陣列的資料類型,並重新分配空間

  2. 將原有的數據,裝換為新的數據類型,重新放到應該在的位置上,且保存順序性

  3. ##再插入新元素

整數集合不支援降級操作,一旦升級就不能降級了。

跳躍表

跳躍表是鍊錶的一種,是一種利用空間換時間的資料結構。跳表平均支援 O(logN),最壞O(N)複雜度的查找。

跳表是由一個zskiplist 和 多個 zskiplistNode 組成。我們先來看看他們的結構:

/* ZSETs use a specialized version of Skiplists *//*
 * 跳跃表节点
 */

typedef struct zskiplistNode {
    // 成员对象
    robj *obj;
    // 分值
    double score;
    // 后退指针
    struct zskiplistNode *backward;
    // 层
    struct zskiplistLevel {
        // 前进指针
        struct zskiplistNode *forward;
        // 跨度
        unsigned int span;
    } level[];

    } zskiplistNode;
        
/*
 * 跳跃表
 */

typedef struct zskiplist {
    // 表头节点和表尾节点
    struct zskiplistNode *header, *tail;
    // 表中节点的数量
    unsigned long length;
    // 表中层数最大的节点的层数
    int level;

} zskiplist;
登入後複製
所以根據這個程式碼我們可以畫出如下的結構圖:

Redis的基礎資料結構是怎麼樣的

其實跳表就是一個利用空間換時間的資料結構,利用level 作為鍊錶的索引。

之前有人問過 Redis 的作者 為什麼要使用跳躍表,而不是 tree 來建立索引?作者的回答是:

  1. 省記憶體。

  2. 在使用ZRANGE或ZREVRANGE時,涉及的是典型的鍊錶操作場景。時間複雜度的表現和平衡樹差不多。

  3. 最重要的一點是跳躍表的實作很簡單就能達到 O(logN)的等級。

壓縮列表

壓縮鍊錶 Redis 作者的介紹是,為了盡可能節省記憶體設計出來的雙向鍊錶。

對於一個壓縮列表程式碼裡註解給出的資料結構如下:

Redis的基礎資料結構是怎麼樣的

zlbytes 表示的是整個壓縮列表使用的記憶體位元組數

zltail 指定了壓縮清單的尾節點的偏移量

##zllen

是壓縮清單entry 的數量

entry

是ziplist 的節點

zlend

標記壓縮清單的末端這個清單中還有單一指標:

ZIPLIST_ENTRY_HEAD

清單開始節點的頭偏移

ZIPLIST_ENTRY_TAIL

清單結束節點的頭偏移

ZIPLIST_ENTRY_END

##ZIPLIST_ENTRY_END

# 列表的尾節點結束的偏移量

再看看一個entry 的結構:

/*
 * 保存 ziplist 节点信息的结构
 */

typedef struct zlentry {
    // prevrawlen :前置节点的长度
    // prevrawlensize :编码 prevrawlen 所需的字节大小
    unsigned int prevrawlensize, prevrawlen;
    // len :当前节点值的长度
    // lensize :编码 len 所需的字节大小  
    unsigned int lensize, len;
    // 当前节点 header 的大小
    // 等于 prevrawlensize + lensize
    unsigned int headersize;
    // 当前节点值所使用的编码类型
    unsigned char encoding;
    // 指向当前节点的指针
    unsigned char *p;

} zlentry;
登入後複製

依序解釋這幾個參數。
prevrawlen 前節點的長度,這裡多了一個 size,其實是記錄了 prevrawlen 的尺寸。 Redis 為了節省記憶體並不是直接使用預設的 int 的長度,而是逐漸升級的。 同理 len 記錄的是目前節點的長度,
lensize 記錄的是 len 的長度。
headersize 就是前文提到的兩個 size 總和。
encoding 就是這個節點的資料型態。這裡注意一下 encoding 的類型只包括整數和字串。

p

節點的指針,不用過多的解釋。

###需要注意一點,因為每個節點都保存了前一個節點的長度,如果發生了更新或刪除節點,則這個節點之後的資料也需要修改,有一種最壞的情況就是如果每個節點都處於需要擴容的零界點,就會造成這個節點之後的節點都要修改size 這個參數,引發連鎖反應。這時候就是 壓縮鍊錶最壞的時間複雜度 O(n^2)。不過所有節點都處於臨界值,這樣的機率可以說比較小。 ###

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

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱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

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

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

redis集群模式怎麼搭建 redis集群模式怎麼搭建 Apr 10, 2025 pm 10:15 PM

Redis集群模式通過分片將Redis實例部署到多個服務器,提高可擴展性和可用性。搭建步驟如下:創建奇數個Redis實例,端口不同;創建3個sentinel實例,監控Redis實例並進行故障轉移;配置sentinel配置文件,添加監控Redis實例信息和故障轉移設置;配置Redis實例配置文件,啟用集群模式並指定集群信息文件路徑;創建nodes.conf文件,包含各Redis實例的信息;啟動集群,執行create命令創建集群並指定副本數量;登錄集群執行CLUSTER INFO命令驗證集群狀態;使

redis數據怎麼清空 redis數據怎麼清空 Apr 10, 2025 pm 10:06 PM

如何清空 Redis 數據:使用 FLUSHALL 命令清除所有鍵值。使用 FLUSHDB 命令清除當前選定數據庫的鍵值。使用 SELECT 切換數據庫,再使用 FLUSHDB 清除多個數據庫。使用 DEL 命令刪除特定鍵。使用 redis-cli 工具清空數據。

redis怎麼讀取隊列 redis怎麼讀取隊列 Apr 10, 2025 pm 10:12 PM

要從 Redis 讀取隊列,需要獲取隊列名稱、使用 LPOP 命令讀取元素,並處理空隊列。具體步驟如下:獲取隊列名稱:以 "queue:" 前綴命名,如 "queue:my-queue"。使用 LPOP 命令:從隊列頭部彈出元素並返回其值,如 LPOP queue:my-queue。處理空隊列:如果隊列為空,LPOP 返回 nil,可先檢查隊列是否存在再讀取元素。

centos redis如何配置Lua腳本執行時間 centos redis如何配置Lua腳本執行時間 Apr 14, 2025 pm 02:12 PM

在CentOS系統上,您可以通過修改Redis配置文件或使用Redis命令來限制Lua腳本的執行時間,從而防止惡意腳本佔用過多資源。方法一:修改Redis配置文件定位Redis配置文件:Redis配置文件通常位於/etc/redis/redis.conf。編輯配置文件:使用文本編輯器(例如vi或nano)打開配置文件:sudovi/etc/redis/redis.conf設置Lua腳本執行時間限制:在配置文件中添加或修改以下行,設置Lua腳本的最大執行時間(單位:毫秒)

redis指令怎麼用 redis指令怎麼用 Apr 10, 2025 pm 08:45 PM

使用 Redis 指令需要以下步驟:打開 Redis 客戶端。輸入指令(動詞 鍵 值)。提供所需參數(因指令而異)。按 Enter 執行指令。 Redis 返迴響應,指示操作結果(通常為 OK 或 -ERR)。

redis怎麼使用鎖 redis怎麼使用鎖 Apr 10, 2025 pm 08:39 PM

使用Redis進行鎖操作需要通過SETNX命令獲取鎖,然後使用EXPIRE命令設置過期時間。具體步驟為:(1) 使用SETNX命令嘗試設置一個鍵值對;(2) 使用EXPIRE命令為鎖設置過期時間;(3) 當不再需要鎖時,使用DEL命令刪除該鎖。

redis命令行怎麼用 redis命令行怎麼用 Apr 10, 2025 pm 10:18 PM

使用 Redis 命令行工具 (redis-cli) 可通過以下步驟管理和操作 Redis:連接到服務器,指定地址和端口。使用命令名稱和參數向服務器發送命令。使用 HELP 命令查看特定命令的幫助信息。使用 QUIT 命令退出命令行工具。

redis過期策略怎麼設置 redis過期策略怎麼設置 Apr 10, 2025 pm 10:03 PM

Redis數據過期策略有兩種:定期刪除:定期掃描刪除過期鍵,可通過 expired-time-cap-remove-count、expired-time-cap-remove-delay 參數設置。惰性刪除:僅在讀取或寫入鍵時檢查刪除過期鍵,可通過 lazyfree-lazy-eviction、lazyfree-lazy-expire、lazyfree-lazy-user-del 參數設置。

See all articles