最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Redis數(shù)據(jù)編碼詳解

 更新時間:2026年03月20日 15:34:26   作者:czlczl20020925  
這篇文章主要介紹了Redis數(shù)據(jù)編碼的相關(guān)知識,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
struct redisObject {
    unsigned type:4;       // [0-3 bit] 對象類型 (如 String)
    unsigned encoding:4;   // [4-7 bit] 編碼方式 (如 int/embstr/raw)
    unsigned lru:24;       // [8-31 bit] 緩存淘汰數(shù)據(jù)
    int refcount;          // [32-63 bit] 引用計數(shù) (4字節(jié))
    void *ptr;             // [64-127 bit] 關(guān)鍵指針 (8字節(jié))
};

String

在 Redis 的底層實現(xiàn)中,String(字符串) 類型并不只有一種形態(tài)。為了平衡“內(nèi)存占用”與“處理性能”,Redis 會根據(jù)字符串的內(nèi)容和長度,在 intembstrraw 三種編碼方式之間自動切換。

這三種編碼都封裝在 redisObject 這個“外殼”下,通過 encoding 字段進行區(qū)分。

struct sdshdr8 {
    uint8_t len;    /* 已使用長度 */
    uint8_t alloc;  /* 總分配空間(不含頭和 \0) */
    unsigned char flags; /* 類型標(biāo)志(如 sdshdr8, sdshdr16 等) */
    char buf[];     /* 實際字節(jié)數(shù)組 */
};

1.int編碼:直接存儲整數(shù)

當(dāng)一個字符串對象保存的是整數(shù)值,且這個整數(shù)可以用 long 類型(8 字節(jié)有符號整數(shù))表示時,Redis 就會使用 int 編碼。

  • 物理特征:它不會分配額外的 SDS 空間,而是直接將整數(shù)值存儲在 redisObject 結(jié)構(gòu)體的 ptr 指針字段中(通過強制類型轉(zhuǎn)換)。
  • 共享對象優(yōu)化:Redis 啟動時會預(yù)先創(chuàng)建 0 ∼ 9999 0 \sim 9999 09999 這 10,000 個整數(shù)對象。如果你存的值在這個范圍內(nèi),所有的 Key 都會指向同一個物理內(nèi)存地址,引用計數(shù)加 1,內(nèi)存開銷幾乎為零。
  • 適用場景:計數(shù)器、ID 存儲等數(shù)值場景。

2.embstr編碼:嵌入式短字符串

當(dāng)字符串的長度 小于等于 44 字節(jié) 時,Redis 使用 embstr 編碼。這是為了極致壓榨小對象的性能。

  • 物理特征redisObjectsdshdr(SDS 頭部及數(shù)據(jù))在內(nèi)存中是連續(xù)的一整塊。它是通過一次 malloc 申請出來的。
  • 核心邏輯
    • 只讀性:它是只讀的,任何修改操作(如 APPEND)都會迫使它先升級為 raw
    • 高性能:由于內(nèi)存連續(xù),CPU 緩存命中率極高,且分配/釋放內(nèi)存只需要一次系統(tǒng)調(diào)用。
  • 計算門檻:44 字節(jié)的限制是為了讓整個對象(16B redisObject + 3B sdshdr8 + 1B \0 + 44B Data)剛好適配內(nèi)存分配器的 64 字節(jié) 內(nèi)存槽位。

3.raw編碼:常規(guī)長字符串

當(dāng)字符串的長度 大于 44 字節(jié),或者對 embstr 進行了修改操作時,Redis 會使用 raw 編碼。

  • 物理特征redisObjectsdshdr 分布在兩塊不連續(xù)的內(nèi)存空間中。ptr 指針指向獨立的 SDS 區(qū)域。
  • 核心邏輯
    • 可擴展性:適合存儲長文本、二進制數(shù)據(jù)或頻繁修改的字符串。
    • 分配代價:創(chuàng)建或銷毀對象需要兩次 mallocfree。
  • 適用場景:JSON 數(shù)據(jù)、序列化后的對象、較大的文本內(nèi)容。

List

Redis3.2之前:ZipList/LinkedList

在 Redis 3.2 之前,List 的實現(xiàn)非常簡單粗暴:當(dāng)數(shù)據(jù)量小時使用 ZipList(壓縮列表),通過連續(xù)內(nèi)存壓榨空間;當(dāng)數(shù)據(jù)量大或字符串長時,直接轉(zhuǎn)換為 LinkedList(雙向鏈表),通過指針實現(xiàn)靈活增刪,但代價是每個節(jié)點都要背負(fù)兩個 8 字節(jié)指針的沉重負(fù)擔(dān),且內(nèi)存碎片極多。

Redis3.2之后:QuickList

RedisObject中的*ptr指向quicklist對象

typedef struct quicklist {
    quicklistNode *head;      /* 指向頭節(jié)點 */
    quicklistNode *tail;      /* 指向尾節(jié)點 */
    unsigned long count;      /* 所有元素總數(shù) */
    unsigned long len;        /* 節(jié)點(車廂)總數(shù) */
    int fill : 16;            /* 節(jié)點填充因子 */
    unsigned int compress : 16; /* 壓縮深度 */
} quicklist;
typedef struct quicklistNode {
    struct quicklistNode *prev; /* 前驅(qū)指針 */
    struct quicklistNode *next; /* 后繼指針 */
    unsigned char *zl;          /* 指向物理內(nèi)存中的連續(xù)塊 (ZipList/Listpack) */
    unsigned int sz;            /* 連續(xù)塊占用的總字節(jié)數(shù) */
    unsigned int count : 16;    /* 連續(xù)塊包含的元素個數(shù) */
    // ... 其他標(biāo)志位
} quicklistNode;

Set

Redis 的 Set(集合) 編碼設(shè)計同樣遵循“從小到大”的進化邏輯。它在物理實現(xiàn)上主要在 IntSet(整數(shù)集合)、Listpack(緊湊列表,Redis 7.2+)Hashtable(哈希表) 之間切換。

它的核心哲學(xué)是:如果全是小整數(shù),我用數(shù)組排好序;如果有字符串,我用哈希表鎖死。

1. 物理結(jié)構(gòu):intset(整數(shù)集合)

當(dāng)集合滿足以下 兩個條件 時,Redis 優(yōu)先使用 intset

  1. 集合內(nèi)所有成員均為 整數(shù)。
  2. 成員數(shù)量小于配置參數(shù) set-max-intset-entries(默認(rèn) 512 個)。

內(nèi)存布局與查找邏輯

intset 是一塊絕對連續(xù)的內(nèi)存空間。

  • 物理存儲:內(nèi)部是一個有序數(shù)組,支持 int16_t、int32_tint64_t 編碼。
  • 有序性:元素在數(shù)組內(nèi)按從小到大嚴(yán)格排序。
  • 查找算法:使用 二分查找(Binary Search),時間復(fù)雜度為 O ( log ? N ) O(\log N) O(logN)
  • 升級邏輯:當(dāng)新插入的整數(shù)超出當(dāng)前位寬(如 int16 存入 int32)時,會觸發(fā)整塊內(nèi)存的重新分配和數(shù)據(jù)遷移。注意,為了保持效率,該過程不可逆(不支持降級)

2. 物理結(jié)構(gòu):listpack(緊湊列表)

這是 Redis 7.2 引入的新物理層。在舊版本中,集合只要出現(xiàn)一個字符串就會立刻膨脹為 dict,而 listpack 充當(dāng)了中間的緩沖帶。

  • 觸發(fā)場景:集合中包含字符串,但成員數(shù)量和單個字符串長度未達到 set-max-listpack-entriesset-max-listpack-value 閾值。
  • 物理特征:連續(xù)字節(jié)流存儲。
  • 性能權(quán)衡:雖然查找復(fù)雜度退化為 O ( N ) O(N) O(N)(順序遍歷),但由于數(shù)據(jù)規(guī)模極小,其內(nèi)存利用率遠高于 dict,且在小數(shù)據(jù)量下,連續(xù)內(nèi)存對 CPU 緩存的友好性抵消了 O ( N ) O(N) O(N) 的算法劣勢。

3. 物理結(jié)構(gòu):dict(字典 / 邏輯名稱 HashTable)

當(dāng)集合規(guī)模超過閾值,或包含長字符串時,Redis 會使用 dict 作為終極物理載體。

物理映射與內(nèi)存布局

此時 redisObject->ptr 指向一個真實的 dict 結(jié)構(gòu)體實例。

  • Key (鍵):存儲集合的成員,指向一個 SDS 字符串對象。
  • Value (值):物理上統(tǒng)一設(shè)置為 NULL 指針。
  • 唯一性保證:直接利用 dict 自身的哈希碰撞處理和 Key 唯一性邏輯實現(xiàn)集合去重。
  • 性能特征:查找復(fù)雜度為 O ( 1 ) O(1) O(1)。支持漸進式 Rehash,在數(shù)據(jù)量極大時仍能保持穩(wěn)定的響應(yīng)速度。

4. 宏觀物理映射:RedisObject 的指向

對于 Set 來說,redisObject 的包裝方式非常直觀:

字段IntSet 編碼Hashtable 編碼
typeOBJ_SETOBJ_SET
encodingOBJ_ENCODING_INTSETOBJ_ENCODING_HT
ptr 指向一整塊連續(xù)的 intset 結(jié)構(gòu)一個復(fù)雜的 dict 字典結(jié)構(gòu)

ZSet

Redis 的 ZSet(有序集合) 在底層編碼上設(shè)計得最為復(fù)雜,因為它必須同時滿足 O ( 1 ) O(1) O(1) 成員查分 O ( log ? N ) O(\log N) O(logN) 按分?jǐn)?shù)排序/范圍檢索 這兩個核心需求。

其物理實現(xiàn)主要分為兩個階段:listpackdict + zskiplist。

1. 緊湊階段:listpack(緊湊列表)

當(dāng) ZSet 滿足以下兩個條件時,Redis 使用 listpack 編碼(OBJ_ENCODING_LISTPACK):

  1. 成員數(shù)量小于 zset-max-listpack-entries(默認(rèn) 128)。
  2. 所有成員字符串長度小于 zset-max-listpack-value(默認(rèn) 64 字節(jié))。

物理存儲邏輯

listpack 內(nèi)部,成員(Member)和分值(Score)被存儲為兩個相鄰的 Entry

  • 布局[Member1, Score1, Member2, Score2, ...]
  • 有序性:內(nèi)部元素按分值(Score)從小到大嚴(yán)格排序。
  • 性能特征:由于是連續(xù)內(nèi)存,插入和查找涉及 O ( N ) O(N) O(N) 的順序遍歷及內(nèi)存搬遷。但在小數(shù)據(jù)量下,這種結(jié)構(gòu)的 CPU 緩存命中率極高,且省去了復(fù)雜的指針開銷。

2. 進化階段:zset結(jié)構(gòu)體 (跳表 + 字典)

當(dāng)數(shù)據(jù)量突破閾值后,redisObject->ptr 會指向一個專門的 zset 結(jié)構(gòu)體。這是一個雙重物理結(jié)構(gòu)的組合:

typedef struct zset {
    dict *dict;          /* 成員 -> 分值的哈希表 */
    zskiplist *zsl;      /* 按分?jǐn)?shù)排序的跳躍表 */
} zset;

A. 物理組件一:dict(字典)

  • 作用:實現(xiàn) O ( 1 ) O(1) O(1) 復(fù)雜度的 ZSCORE 操作。
  • 邏輯:Key 是成員(SDS),Value 是分值(double)。
  • 必要性:如果沒有 dict,查找一個成員的分?jǐn)?shù)需要遍歷跳表,復(fù)雜度為 O ( log ? N ) O(\log N) O(logN)

B. 物理組件二:zskiplist(跳躍表)

  • 作用:實現(xiàn)高效的范圍查詢(ZRANGE)和排名計算(ZRANK)。
  • 邏輯:節(jié)點按分?jǐn)?shù)排序。每個節(jié)點包含多個層級的指針,支持快速跳躍尋址。
  • 性能:平均查找復(fù)雜度為 O ( log ? N ) O(\log N) O(logN)。

3. 內(nèi)存優(yōu)化:SDS 的“引用共享”

你可能會擔(dān)心:同一個成員既存在 dict 里,又存在 zskiplist 里,豈不是浪費了一倍內(nèi)存?

物理真相
dict 的 Key 和 zskiplistNodeele 指向的是同一個物理內(nèi)存地址(同一個 SDS 對象)。

  • Redis 只是在兩個數(shù)據(jù)結(jié)構(gòu)中各存了一個 指針。
  • 這種設(shè)計通過增加少量指針開銷(每個節(jié)點約幾十字節(jié)),換取了兩個維度的極致查詢速度。

4. 物理特性對比表

物理結(jié)構(gòu)邏輯編碼 (Encoding)核心優(yōu)勢算法復(fù)雜度內(nèi)存特征
listpackLISTPACK極致節(jié)省內(nèi)存O ( N ) O(N) O(N) (查找/插入)連續(xù)內(nèi)存,無碎片
zset (復(fù)合)SKIPLIST全能性能查分 O ( 1 ) O(1) O(1),范圍 O ( log ? N ) O(\log N) O(logN)雙重索引,指針較多

5. 狀態(tài)轉(zhuǎn)換邏輯

ZSet 的轉(zhuǎn)換通常是單向不可逆的:

  • 一旦數(shù)據(jù)量超過閾值,listpack 會被拆解,重新裝載進一個新的 dictzskiplist 中。
  • 原因:從復(fù)雜的雙重結(jié)構(gòu)回退到連續(xù)內(nèi)存塊涉及大規(guī)模的內(nèi)存重分配和 CPU 計算,收益不抵成本。

Hash

Redis 的 Hash(哈希) 結(jié)構(gòu)在底層編碼的設(shè)計上,邏輯與 ZSet 非常相似:在數(shù)據(jù)量小時采用緊湊的連續(xù)內(nèi)存,在數(shù)據(jù)量大時進化為散列表。

目前的物理實現(xiàn)主要分為 listpackdict 兩種。

1. 緊湊編碼:listpack(緊湊列表)

當(dāng) Hash 結(jié)構(gòu)滿足以下兩個條件時,Redis 使用 listpack 存儲(編碼名稱為 OBJ_ENCODING_LISTPACK):

  1. 哈希中字段(Field)的數(shù)量小于 hash-max-listpack-entries(默認(rèn) 512 個)。
  2. 所有字段名和值的長度都小于 hash-max-listpack-value(默認(rèn) 64 字節(jié))。

物理存儲邏輯

listpack 的字節(jié)流中,F(xiàn)ield 和 Value 是作為兩個相鄰的 Entry 存儲的:

  • 布局[Field1, Value1, Field2, Value2, ...]
  • 查找方式:完全依靠順序遍歷。由于內(nèi)存是絕對連續(xù)的,CPU 在讀取時可以利用預(yù)取機制(Prefetching),在小規(guī)模數(shù)據(jù)下速度極快。
  • 內(nèi)存優(yōu)勢:沒有指針開銷,沒有內(nèi)存對齊的空隙,空間利用率達到極致。

2. 散列編碼:dict(字典)

一旦數(shù)據(jù)量突破閾值,或者某個 Value 太長,Redis 就會將物理結(jié)構(gòu)轉(zhuǎn)換為 dict(編碼名稱為 OBJ_ENCODING_HT)。

物理實現(xiàn)邏輯

此時 redisObject->ptr 指向一個真實的 dict 結(jié)構(gòu)體:

  • Key (鍵):存儲的是 Hash 的字段名(Field),物理上是一個 SDS 對象。
  • Value (值):存儲的是 Hash 的字段值(Value),物理上同樣是一個 SDS 對象。
  • 沖突處理:使用拉鏈法(鏈地址法)解決哈希沖突。
  • 性能特征:查找、插入和刪除的復(fù)雜度均為 O ( 1 ) O(1) O(1)。

到此這篇關(guān)于Redis數(shù)據(jù)編碼詳解的文章就介紹到這了,更多相關(guān)redis數(shù)據(jù)編碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Redis的過期策略以及內(nèi)存淘汰機制詳解

    Redis的過期策略以及內(nèi)存淘汰機制詳解

    文章詳解Redis的過期策略(定時刪除、惰性刪除、定時掃描)和緩存淘汰算法(如LFU、LRU等),強調(diào)定時掃描通過隨機抽樣處理過期鍵,惰性刪除在訪問時清除過期鍵,同時指出需避免大量鍵同時過期,且主從同步延遲可能導(dǎo)致數(shù)據(jù)不一致,建議業(yè)務(wù)中合理設(shè)置過期時間與淘汰策略
    2025-08-08
  • 使用Redis實現(xiàn)分布式鎖的方法

    使用Redis實現(xiàn)分布式鎖的方法

    為了保證我們線上服務(wù)的并發(fā)性和安全性,目前我們的服務(wù)一般拋棄了單體應(yīng)用,采用的都是擴展性很強的分布式架構(gòu),這篇文章主要介紹了使用Redis實現(xiàn)分布式鎖的方法,需要的朋友可以參考下
    2022-06-06
  • Redis在項目中的使用(JedisPool方式)

    Redis在項目中的使用(JedisPool方式)

    項目操作redis是使用的RedisTemplate方式,另外還可以完全使用JedisPool和Jedis來操作redis,本文給大家介紹Redis在項目中的使用,JedisPool方式,感興趣的朋友跟隨小編一起看看吧
    2021-12-12
  • Redis源碼解析sds字符串實現(xiàn)示例

    Redis源碼解析sds字符串實現(xiàn)示例

    這篇文章主要為大家介紹了Redis源碼解析sds字符串實現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • 詳解redis集群選舉機制

    詳解redis集群選舉機制

    這篇文章主要介紹了詳解redis集群選舉機制,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • Redis為什么快如何實現(xiàn)高可用及持久化

    Redis為什么快如何實現(xiàn)高可用及持久化

    這篇文章主要介紹了Redis為什么快如何實現(xiàn)高可用及持久化,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • 單線程Redis快的4 個原因總結(jié)

    單線程Redis快的4 個原因總結(jié)

    作為內(nèi)存中數(shù)據(jù)存儲,Redis 以其速度和性能著稱,通常被用作大多數(shù)后端服務(wù)的緩存解決方案,但是,在內(nèi)部,Redis 采用單線程架構(gòu),為什么單線程設(shè)計依然會有這么高的性能,在本文中,讓我們深入探討為什么 Redis 才有單線程架構(gòu)
    2023-07-07
  • redis 替代php文件存儲session的實例

    redis 替代php文件存儲session的實例

    這篇文章主要介紹了redis 替代php文件存儲session的實例的相關(guān)資料,希望通過本文能幫助到大家,讓大家掌握這樣的方法,需要的朋友可以參考下
    2017-10-10
  • CentOS7.5使用mysql_multi方式安裝MySQL5.7.28多實例(詳解)

    CentOS7.5使用mysql_multi方式安裝MySQL5.7.28多實例(詳解)

    這篇文章主要介紹了CentOS7.5使用mysql_multi方式安裝MySQL5.7.28多實例,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-01-01
  • Redis數(shù)據(jù)結(jié)構(gòu)之listpack和quicklist使用學(xué)習(xí)

    Redis數(shù)據(jù)結(jié)構(gòu)之listpack和quicklist使用學(xué)習(xí)

    這篇文章主要為大家介紹了Redis數(shù)據(jù)結(jié)構(gòu)之listpack和quicklist的使用學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-07-07

最新評論

兴山县| 无为县| 温泉县| 昭苏县| 甘南县| 浏阳市| 当阳市| 舟曲县| 隆回县| 错那县| 油尖旺区| 连南| 阳山县| 甘谷县| 镇巴县| 榆中县| 竹北市| 佛教| 巴彦淖尔市| 页游| 大港区| 昂仁县| 仁布县| 旌德县| 洮南市| 交城县| 华亭县| 壤塘县| 曲阜市| 栖霞市| 江华| 宁南县| 嘉祥县| 临沧市| 莱州市| 田林县| 郎溪县| 林州市| 宝山区| 石台县| 如东县|