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

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

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

String

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

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

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

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

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

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

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

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

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

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

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

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

List

Redis3.2之前:ZipList/LinkedList

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

Redis3.2之后:QuickList

RedisObject中的*ptr指向quicklist對(duì)象

typedef struct quicklist {
    quicklistNode *head;      /* 指向頭節(jié)點(diǎn) */
    quicklistNode *tail;      /* 指向尾節(jié)點(diǎn) */
    unsigned long count;      /* 所有元素總數(shù) */
    unsigned long len;        /* 節(jié)點(diǎn)(車廂)總數(shù) */
    int fill : 16;            /* 節(jié)點(diǎn)填充因子 */
    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ù)塊包含的元素個(gè)數(shù) */
    // ... 其他標(biāo)志位
} quicklistNode;

Set

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ZSet

Redis 的 ZSet(有序集合) 在底層編碼上設(shè)計(jì)得最為復(fù)雜,因?yàn)樗仨毻瑫r(shí)滿足 O ( 1 ) O(1) O(1) 成員查分 O ( log ? N ) O(\log N) O(logN) 按分?jǐn)?shù)排序/范圍檢索 這兩個(gè)核心需求。

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

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

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

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

物理存儲(chǔ)邏輯

listpack 內(nèi)部,成員(Member)和分值(Score)被存儲(chǔ)為兩個(gè)相鄰的 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. 進(jìn)化階段:zset結(jié)構(gòu)體 (跳表 + 字典)

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

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

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

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

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

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

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

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

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

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

4. 物理特性對(duì)比表

物理結(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 會(huì)被拆解,重新裝載進(jìn)一個(gè)新的 dictzskiplist 中。
  • 原因:從復(fù)雜的雙重結(jié)構(gòu)回退到連續(xù)內(nèi)存塊涉及大規(guī)模的內(nèi)存重分配和 CPU 計(jì)算,收益不抵成本。

Hash

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

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

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

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

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

物理存儲(chǔ)邏輯

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

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

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

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

物理實(shí)現(xiàn)邏輯

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

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

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

相關(guān)文章

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

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

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

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

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

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

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

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

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

    詳解redis集群選舉機(jī)制

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

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

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

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

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

    redis 替代php文件存儲(chǔ)session的實(shí)例

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

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

    這篇文章主要介紹了CentOS7.5使用mysql_multi方式安裝MySQL5.7.28多實(shí)例,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    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í),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07

最新評(píng)論

新津县| 甘德县| 太白县| 新津县| 大石桥市| 浪卡子县| 孙吴县| 温泉县| 甘洛县| 左贡县| 东至县| 吴江市| 满洲里市| 佛冈县| 长治市| 城步| 青龙| 甘泉县| 定陶县| 深泽县| 淄博市| 通渭县| 东宁县| 寿光市| 辛集市| 重庆市| 北票市| 抚远县| 勃利县| 屯留县| 三都| 玉山县| 贵定县| 林西县| 清流县| 西乌| 社会| 广宁县| 射阳县| 安达市| 绿春县|