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

Redis中Set結(jié)構(gòu)使用過程與原理說明

 更新時(shí)間:2025年09月29日 11:19:23   作者:你是橙子那我是誰  
本文解析了Redis Set數(shù)據(jù)結(jié)構(gòu),涵蓋其基本操作(如添加、查找)、集合運(yùn)算(交并差)、底層實(shí)現(xiàn)(intset與hashtable自動切換機(jī)制)、典型應(yīng)用場景(如去重、社交關(guān)系)及性能優(yōu)化策略,強(qiáng)調(diào)其高效性和靈活性

開篇:從購物車到Redis Set

想象一下你在網(wǎng)上購物時(shí),把商品加入購物車的場景。當(dāng)你點(diǎn)擊"加入購物車"按鈕時(shí),系統(tǒng)需要確保同一件商品不會被重復(fù)添加,同時(shí)又能快速判斷某件商品是否已經(jīng)在購物車中。這種場景下,Redis的Set數(shù)據(jù)結(jié)構(gòu)就像是一個(gè)完美的購物車容器。

Redis中的Set是一個(gè)無序的、不重復(fù)的字符串集合,它提供了高效的添加、刪除和查找操作。就像購物車能自動去重一樣,Set結(jié)構(gòu)天然支持去重功能。在實(shí)際應(yīng)用中,Set常被用于存儲用戶標(biāo)簽、好友關(guān)系、投票系統(tǒng)等場景。今天,我們就來深入探討Redis Set的使用方法和內(nèi)部實(shí)現(xiàn)原理。

一、Redis Set的基本操作

理解了Set的應(yīng)用場景后,我們來看看Redis Set提供的基本操作。這些操作就像購物車的各種功能按鈕,讓我們能夠方便地管理集合中的元素。

1.1 常用命令

// 添加元素到集合
SADD myset "item1" "item2" "item3"

// 獲取集合中的所有元素
SMEMBERS myset

// 判斷元素是否在集合中
SISMEMBER myset "item1"

// 獲取集合元素?cái)?shù)量
SCARD myset

// 隨機(jī)移除并返回一個(gè)元素
SPOP myset

// 隨機(jī)返回一個(gè)元素但不移除
SRANDMEMBER myset

上述代碼展示了Redis Set的基本操作命令。SADD用于添加元素,SMEMBERS查看所有元素,SISMEMBER檢查元素是否存在,SCARD獲取元素?cái)?shù)量,SPOP和SRANDMEMBER用于隨機(jī)操作元素。

以上流程圖說明了Redis Set的基本操作流程。從添加元素開始,到查看、檢查、統(tǒng)計(jì)和隨機(jī)操作,形成了一個(gè)完整的數(shù)據(jù)操作閉環(huán)。

1.2 集合運(yùn)算

Redis Set還支持豐富的集合運(yùn)算,這些運(yùn)算在實(shí)際開發(fā)中非常有用:

// 求兩個(gè)集合的差集
SDIFF set1 set2

// 求兩個(gè)集合的交集
SINTER set1 set2

// 求兩個(gè)集合的并集
SUNION set1 set2

// 將差集/交集/并集結(jié)果存儲到新集合
SDIFFSTORE newset set1 set2
SINTERSTORE newset set1 set2
SUNIONSTORE newset set1 set2

這些集合運(yùn)算 命令可以用于各種數(shù)據(jù)分析場景,比如找出兩個(gè)用戶群的共同好友(SINTER),或者找出A用戶有但B用戶沒有的好友(SDIFF)。

這個(gè)圖展示了Redis Set的三種基本集合運(yùn)算:差集、交集和并集。通過不同的運(yùn)算,我們可以從原始集合中提取出有價(jià)值的信息。

二、Redis Set的內(nèi)部實(shí)現(xiàn)

了解了基本操作后,我們來看看Redis Set的內(nèi)部實(shí)現(xiàn)原理。就像了解購物車的構(gòu)造能幫助我們更好地使用它一樣,理解Set的內(nèi)部實(shí)現(xiàn)能讓我們更高效地使用Redis。

2.1 數(shù)據(jù)結(jié)構(gòu)選擇

Redis Set的底層實(shí)現(xiàn)有兩種數(shù)據(jù)結(jié)構(gòu),根據(jù)元素?cái)?shù)量和元素大小自動選擇:

  1. intset(整數(shù)集合):當(dāng)集合中所有元素都是整數(shù)且元素?cái)?shù)量較少時(shí)使用
  2. hashtable(哈希表):當(dāng)集合包含非整數(shù)元素或元素?cái)?shù)量較多時(shí)使用

這種智能選擇的設(shè)計(jì)就像我們根據(jù)購物物品的多少選擇不同大小的購物車一樣,既節(jié)省空間又保證效率。

這個(gè)狀態(tài)圖展示了Redis選擇Set底層數(shù)據(jù)結(jié)構(gòu)的過程。首先檢查元素類型和數(shù)量,然后決定使用intset還是hashtable。

2.2 intset實(shí)現(xiàn)原理詳解

intset是Redis為整數(shù)集合優(yōu)化設(shè)計(jì)的一種緊湊數(shù)據(jù)結(jié)構(gòu),它的核心特點(diǎn)包括:

2.2.1 內(nèi)存布局

intset的內(nèi)存布局非常緊湊,由三部分組成:

struct intset {
    uint32_t encoding;  // 編碼方式:INTSET_ENC_INT16/32/64
    uint32_t length;    // 元素?cái)?shù)量
    int8_t contents[];  // 實(shí)際存儲數(shù)組
};

這個(gè)結(jié)構(gòu)體展示了intset的內(nèi)存布局。encoding表示元素使用的位數(shù)(16/32/64),length是元素?cái)?shù)量,contents是柔性數(shù)組,實(shí)際存儲元素?cái)?shù)據(jù)。

2.2.2 編碼升級機(jī)制

intset有一個(gè)獨(dú)特的特性:當(dāng)插入的元素超過當(dāng)前編碼范圍時(shí),會自動升級編碼:

  1. 初始創(chuàng)建時(shí)默認(rèn)使用16位(INTSET_ENC_INT16)編碼
  2. 當(dāng)插入32位整數(shù)時(shí),升級為32位編碼(INTSET_ENC_INT32)
  3. 當(dāng)插入64位整數(shù)時(shí),升級為64位編碼(INTSET_ENC_INT64)

升級過程需要重新分配內(nèi)存并轉(zhuǎn)換所有現(xiàn)有元素,這是一個(gè)O(N)操作。

這個(gè)序列圖展示了intset編碼升級的過程。當(dāng)插入超過當(dāng)前編碼范圍的數(shù)值時(shí),Redis會自動升級編碼并轉(zhuǎn)換所有現(xiàn)有元素。

2.2.3 查找與插入

intset使用二分查找來定位元素,保證O(logN)的查找復(fù)雜度:

// 偽代碼展示intset查找過程
int search(intset *is, int64_t value) {
    int low = 0, high = is->length-1;
    while(low <= high) {
        int mid = (low + high)/2;
        int64_t midval = _intsetGet(is, mid);
        if (value < midval) high = mid - 1;
        else if (value > midval) low = mid + 1;
        else return mid; // 找到
    }
    return -1; // 未找到
}

這段偽代碼展示了intset的二分查找實(shí)現(xiàn)。由于元素是有序存儲的,可以使用二分查找快速定位元素位置。

2.3 hashtable實(shí)現(xiàn)原理詳解

當(dāng)Set使用hashtable實(shí)現(xiàn)時(shí),實(shí)際上與Redis的Hash類型使用相同的字典結(jié)構(gòu),只是value被設(shè)置為NULL。讓我們深入分析其實(shí)現(xiàn)細(xì)節(jié):

2.3.1 字典結(jié)構(gòu)

Redis字典的核心結(jié)構(gòu)如下:

typedef struct dict {
    dictType *type;     // 類型特定函數(shù)
    void *privdata;     // 私有數(shù)據(jù)
    dictht ht[2];       // 哈希表(兩個(gè)用于rehash)
    long rehashidx;     // rehash進(jìn)度,-1表示未進(jìn)行
    unsigned long iterators; // 正在運(yùn)行的迭代器數(shù)量
} dict;

typedef struct dictht {
    dictEntry **table;      // 哈希表數(shù)組
    unsigned long size;     // 表大小
    unsigned long sizemask; // 大小掩碼,用于計(jì)算索引值
    unsigned long used;     // 已使用節(jié)點(diǎn)數(shù)量
} dictht;

typedef struct dictEntry {
    void *key;              // 鍵
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
        double d;
    } v;                    // 值(Set中為NULL)
    struct dictEntry *next; // 指向下個(gè)哈希表節(jié)點(diǎn),形成鏈表
} dictEntry;

這些結(jié)構(gòu)體定義了Redis字典的核心實(shí)現(xiàn)。dict是頂層結(jié)構(gòu),包含兩個(gè)dictht用于漸進(jìn)式rehash,dictEntry是實(shí)際的鍵值對節(jié)點(diǎn)。

2.3.2 哈希算法與沖突解決

Redis使用MurmurHash2算法計(jì)算鍵的哈希值,然后通過取模確定索引位置:

// 計(jì)算鍵的哈希值
hash = dict->type->hashFunction(key);
// 計(jì)算索引位置
index = hash & dict->ht[0].sizemask;

當(dāng)發(fā)生哈希沖突時(shí),Redis使用鏈地址法解決沖突,即在同一個(gè)索引位置形成鏈表。

這個(gè)圖展示了Redis哈希表的鏈?zhǔn)經(jīng)_突解決方法。相同索引位置的元素通過鏈表連接起來。

2.3.3 漸進(jìn)式rehash

當(dāng)哈希表需要擴(kuò)容時(shí),Redis使用漸進(jìn)式rehash策略:

  1. 為ht[1]分配更大的空間(通常是原大小的2倍)
  2. 設(shè)置rehashidx=0,開始rehash
  3. 每次對字典執(zhí)行操作時(shí),順帶將ht[0]中的一個(gè)索引上的所有鍵值對rehash到ht[1]
  4. 當(dāng)所有鍵值對都遷移完成后,釋放ht[0],將ht[1]設(shè)置為ht[0]

這種策略避免了集中式rehash帶來的性能問題。

這個(gè)用戶旅程圖展示了漸進(jìn)式rehash的完整過程。從初始化到逐步遷移,最后完成整個(gè)rehash操作。

三、Set的應(yīng)用場景與最佳實(shí)踐

掌握了Set的基本操作和實(shí)現(xiàn)原理后,我們來看看它在實(shí)際開發(fā)中的應(yīng)用場景和使用技巧。

3.1 典型應(yīng)用場景

Redis Set在實(shí)際項(xiàng)目中有許多經(jīng)典應(yīng)用:

  1. 用戶標(biāo)簽系統(tǒng):每個(gè)用戶的標(biāo)簽存儲為一個(gè)Set
  2. 社交關(guān)系:用戶的好友、關(guān)注列表可以用Set存儲
  3. 抽獎系統(tǒng):使用SPOP實(shí)現(xiàn)隨機(jī)抽獎
  4. 共同好友/興趣:使用SINTER計(jì)算用戶間的共同點(diǎn)
  5. 黑白名單:使用Set實(shí)現(xiàn)高效的存在性檢查

這個(gè)思維導(dǎo)圖總結(jié)了Redis Set的主要應(yīng)用場景。從用戶標(biāo)簽到社交關(guān)系,從抽獎系統(tǒng)到黑白名單,Set都能發(fā)揮重要作用。

3.2 性能優(yōu)化建議

為了充分發(fā)揮Redis Set的性能,我有以下建議:

  • 對于小型集合(元素少且都是整數(shù)),盡量保持使用intset
  • 大型集合操作(SINTER/SUNION等)可能會阻塞Redis,考慮在從節(jié)點(diǎn)執(zhí)行
  • 頻繁的SPOP操作可以考慮結(jié)合管道(pipeline)批量執(zhí)行
  • 超大集合(百萬級以上)的SMEMBERS操作要謹(jǐn)慎,可能消耗大量內(nèi)存

這個(gè)用戶旅程圖展示了Redis Set性能優(yōu)化的關(guān)鍵點(diǎn)。從小集合處理到大集合操作,再到日常使用習(xí)慣,每個(gè)環(huán)節(jié)都有相應(yīng)的優(yōu)化策略。

四、總結(jié)

通過今天的討論,我們對Redis Set有了全面的認(rèn)識。讓我們總結(jié)一下本文的主要內(nèi)容:

  1. 基本操作:SADD/SMEMBERS/SISMEMBER等命令的使用
  2. 集合運(yùn)算:SDIFF/SINTER/SUNION等集合操作
  3. 內(nèi)部實(shí)現(xiàn):intset的內(nèi)存布局和編碼升級機(jī)制,hashtable的字典結(jié)構(gòu)和漸進(jìn)式rehash
  4. 應(yīng)用場景:標(biāo)簽系統(tǒng)、社交關(guān)系、抽獎等典型應(yīng)用
  5. 性能優(yōu)化:大小集合的不同處理策略和日常優(yōu)化建議

Redis Set是一個(gè)功能強(qiáng)大且高效的數(shù)據(jù)結(jié)構(gòu),正確使用它可以極大地簡化我們的開發(fā)工作。

希望這篇文章能幫助大家更好地理解和應(yīng)用Redis Set。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Redis Desktop Manager(Redis可視化工具)安裝及使用圖文教程

    Redis Desktop Manager(Redis可視化工具)安裝及使用圖文教程

    這篇文章主要介紹了Redis Desktop Manager(Redis可視化工具)安裝及使用圖文教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • Redis?SortedSet數(shù)據(jù)類型及其常用命令總結(jié)

    Redis?SortedSet數(shù)據(jù)類型及其常用命令總結(jié)

    Redis的SortedSet是一個(gè)可排序的set集合,與Java中的TreeSet有些類似,但底層數(shù)據(jù)結(jié)構(gòu)卻差別很大,這篇文章主要介紹了Redis?SortedSet數(shù)據(jù)類型及其常用命令詳解,需要的朋友可以參考下
    2024-06-06
  • Redis Lua腳本的使用教程

    Redis Lua腳本的使用教程

    在Redis的學(xué)習(xí)中,Lua腳本是一項(xiàng)強(qiáng)大的高級特性,它允許用戶在Redis中執(zhí)行復(fù)雜的操作,本文就來介紹一下Redis Lua,腳本的使用教程,感興趣的可以了解一下
    2024-03-03
  • Redis定時(shí)任務(wù)原理的實(shí)現(xiàn)

    Redis定時(shí)任務(wù)原理的實(shí)現(xiàn)

    本文主要是基于?redis?6.2?源碼進(jìn)行分析定時(shí)事件的數(shù)據(jù)結(jié)構(gòu)和常見操作,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Redis出現(xiàn)中文亂碼的問題及解決

    Redis出現(xiàn)中文亂碼的問題及解決

    這篇文章主要介紹了Redis出現(xiàn)中文亂碼的問題及解決,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-06-06
  • Redis系列之底層數(shù)據(jù)結(jié)構(gòu)SDS詳解

    Redis系列之底層數(shù)據(jù)結(jié)構(gòu)SDS詳解

    SDS(簡單動態(tài)字符串)是Redis使用的核心數(shù)據(jù)結(jié)構(gòu),用于替代C語言的字符串,以解決長度獲取慢、內(nèi)存溢出等問題,SDS通過預(yù)分配與惰性釋放策略優(yōu)化內(nèi)存使用,增強(qiáng)安全性,且能存儲文本與二進(jìn)制數(shù)據(jù),可查看源碼src/sds.h和src/sds.c了解更多
    2024-11-11
  • Redis sort 排序命令詳解

    Redis sort 排序命令詳解

    這篇文章主要介紹了Redis sort 排序命令詳解,本文講解了默認(rèn)排序命令、排序方式命令、BY語法、GET用法示例等內(nèi)容,需要的朋友可以參考下
    2015-07-07
  • Redis存取序列化與反序列化性能問題詳解

    Redis存取序列化與反序列化性能問題詳解

    這篇文章主要給大家介紹了關(guān)于Redis存取序列化與反序列化性能問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • 使用Redis實(shí)現(xiàn)分布式鎖的代碼演示

    使用Redis實(shí)現(xiàn)分布式鎖的代碼演示

    edis作為一個(gè)高性能的內(nèi)存數(shù)據(jù)庫,提供了多種機(jī)制來實(shí)現(xiàn)分布式鎖,本文將詳細(xì)介紹如何使用Redis實(shí)現(xiàn)分布式鎖,感興趣的朋友一起看看吧
    2025-04-04
  • Spring Boot 中的 Redis 分布式鎖

    Spring Boot 中的 Redis 分布式鎖

    這篇文章主要介紹了Spring Boot 中的 Redis 分布式鎖及,Redis分布式鎖的優(yōu)化需要的朋友可以參考下
    2023-10-10

最新評論

定远县| 闵行区| 罗江县| 潼关县| 贺州市| 嵊泗县| 汾西县| 珲春市| 池州市| 钟山县| 保靖县| 甘孜县| 荆州市| 水城县| 罗江县| 瓮安县| 梅州市| 保靖县| 延寿县| 德令哈市| 新营市| 福安市| 长丰县| 安徽省| 临泽县| 荥经县| 林口县| 凤山县| 藁城市| 济南市| 鹤庆县| 枞阳县| 芒康县| 津南区| 安义县| 康定县| 晋中市| 义马市| 沽源县| 建宁县| 南宁市|