Redis數據結構SDS,IntSet,Dict

目錄

1.字符串:SDS

1.1.為什么叫做動態字符串

2.IntSet

2.1.inset如何保存大于當前編碼的最大數字?

3.Dict

3.1Dict的擴容

3.2Dict的收縮

3.3.rehash


1.字符串:SDS

SDS的底層是C語言編寫的構建的一種簡單動態字符串?簡稱SDS,是redis比較常見的數據結構。

由于以下幾種缺點,Redis并沒有直接采用C語言的字符串。

1.獲取長度需要計算

2.非二進制安全 :中間不能有 \0,否則就中斷。

3.不可修改 :char * s = "hello"??

在這里Redis會在底層的創建兩個SDS,一個是 “key” 的SDS ,一個是value。

由于不能直接采用C語言字符串,所以采用了一個結構體

注意:len的比特位數每一位就是單位是字節

舉例:對于name字符串來說,redis底層的SDS結構體中,長度是4字節,向內存申請的字節數是4字節,flags則表示不同的編碼格式

編碼格式有什么作用?

核心目的是優化內存使用 和 操作效率?對于不同長度的字符串可以使用不同的頭結構。

1.1.為什么叫做動態字符串

因為它具備動態擴容能力,好比一個 “hy”字符串的SDS

len:2alloc:2flags:1hy\0

如果要給它追加字符”Boy“,那么它首先會申請新的內存空間

如果新的字符串空間 <?1M,那么新空間是擴展后的2倍+1

如果新的字符串空間 > 1M,那么新空間是擴展后字符串長度 + 1M + 1

這個就是內存預分配。

len:5alloc:11flags:1hyBoy\0

優點:

1.獲取字符串的長度時間復雜度為O(1)

2.支持動態擴容

3.二進制安全(中間可以有\0存在)

4.減少內存分配次數


2.IntSet

IntSet是Redis中集合的一種實現方式,基于整數數組來實現,并且具備長度可變,有序的特征。

encoding包含三種工作模式,表示儲存的整數大小不同:

分別可儲存2字節整數,4字節整數,8字節整數。

如果IntSet中儲存三個數那么它的儲存結構應該是這樣的:采用默認的encoding,每個數字2字節

length大小是元素的個數,contents數組保存元素。

2.1.inset如何保存大于當前編碼的最大數字?

當encoding采用int16_t 也就是2個字節大小來存放每個數字,所以每個數字不應該超過兩個字節,最大是32767。當存下99999時會升級編碼的方式去找到合適大小.

如圖是升級編碼前后的contents數組占用空間大小的情況

1.升級編碼到INT_32,每個數字占4字節

2.依次將每個元素向后拷貝到正確的位置

3.將要添加的元素放入末尾

4.最后將encoding的屬性改為INT_32,length的值更新。

源碼:

intset *intsetAdd(intset *is, int64_t value, uint8_t *success) {uint8_t valenc = _intsetValueEncoding(value);// 獲取當前值編碼uint32_t pos; // 要插入的位置if (success) *success = 1;// 判斷編碼是不是超過了當前intset的編碼if (valenc > intrev32ifbe(is->encoding)) {// 超出編碼,需要升級return intsetUpgradeAndAdd(is,value);} else {// 在當前intset中查找值與value一樣的元素的角標posif (intsetSearch(is,value,&pos)) {if (success) *success = 0; //如果找到了,則無需插入,直接結束并返回失敗return is;}// 數組擴容is = intsetResize(is,intrev32ifbe(is->length)+1);// 移動數組中pos之后的元素到pos+1,給新元素騰出空間if (pos < intrev32ifbe(is->length)) intsetMoveTail(is,pos,pos+1);}// 插入新元素_intsetSet(is,pos,value);// 重置元素長度is->length = intrev32ifbe(intrev32ifbe(is->length)+1);return is;
}
static intset* intsetUpgradeAndAdd(intset* is, int64_t value) {// 獲取當前intset編碼uint8_t curenc = intrev32ifbe(is->encoding);// 獲取新編碼uint8_t newenc = _intsetValueEncoding(value);// 獲取元素個數int length = intrev32ifbe(is->length);// 判斷新元素是大于0還是小于0 ,小于0插入隊首、大于0插入隊尾int prepend = value < 0 ? 1 : 0;// 重置編碼為新編碼is->encoding = intrev32ifbe(newenc);// 重置數組大小is = intsetResize(is, intrev32ifbe(is->length) + 1);// 倒序遍歷,逐個搬運元素到新的位置,_intsetGetEncoded按照舊編碼方式查找舊元素while (length--) // _intsetSet按照新編碼方式插入新元素_intsetSet(is, length + prepend, _intsetGetEncoded(is, length, curenc));/* 插入新元素,prepend決定是隊首還是隊尾*/if (prepend)_intsetSet(is, 0, value);else_intsetSet(is, intrev32ifbe(is->length), value);// 修改數組長度is->length = intrev32ifbe(intrev32ifbe(is->length) + 1);return is;
}

總結:

1.InSet確保元素唯一,有序

2.具備類型升級,可以節省空間

3.底層采用二分查找來查詢元素

4.如果數組過長,擴容時移動元素效率不高


3.Dict

Redis是一種鍵-值型的數據庫,那么鍵和值間關系的維護就要靠Dict維護。

Dict是由三部分組成,分別是哈希表(DictHashTable) ,哈希節點(DictEntry),字典(Dict)

當向Dict添加鍵值對時,Redis首先根據key計算哈希值(h),然后利用 h & sizemask(圖上掩碼)計算出元素應放索引的位置,假設哈希值 h = 1, 則 1 & 3 = 1, 因此儲存到角標1位

一個Dict包含兩個hash表,其中一個一般是空,rehash才使用,比如負載因子超過閾值,擴展,收縮,初始化時使用。

3.1Dict的擴容

DIct中的HashTable就是數組結合單項鏈表實現,當集合中的元素過多必然導致hash沖突,同時鏈表過長hash的查詢效率也會越來越低。

每次新增鍵值都會查詢負載因子(LoadFactor = used / size)

1.如果LoadFactor >= 1 同時服務器沒有執行BGSAVE/BGREWRITEAOF等后臺進程。

2.哈希表的LoadFactor > 5,此時就算后臺執行進程也會強制擴容。

擴容的大小為used + 1,以下是擴容操源碼

static int _dictExpandIfNeeded(dict *d){// 如果正在rehash,則返回okif (dictIsRehashing(d)) return DICT_OK;? ? // 如果哈希表為空,則初始化哈希表為默認大小:4if (d->ht[0].size == 0) return dictExpand(d, DICT_HT_INITIAL_SIZE);// 當負載因子(used/size)達到1以上,并且當前沒有進行bgrewrite等子進程操作// 或者負載因子超過5,則進行 dictExpand ,也就是擴容if (d->ht[0].used >= d->ht[0].size &&(dict_can_resize || d->ht[0].used/d->ht[0].size > dict_force_resize_ratio){// 擴容大小為used + 1,底層會對擴容大小做判斷,實際上找的是第一個大于等于 used+1 的 2^nreturn dictExpand(d, d->ht[0].used + 1);}return DICT_OK;
}

首先判斷是否正在rehash 是就返回ok,否則向下執行。如果哈希表是空的就會初始化4個單位,

如果負載因子 >=?1 ,并且沒有進行后臺進程 或者 負載因子>= 5. 開始進行擴容。

3.2Dict的收縮

DIct除擴容之外還可以 收縮,每次執行刪除后如果 負載因子 < 0.1 就會執行。

3.3.rehash

不管是擴容還是收縮,每次變化都會導致size 和 sizemask(掩碼)變化,而key的查詢與sizemask有關。所以必須對哈希表中每一個key重新計算索引,插入新的哈希表,這個過程就是rehash。

1.重新計算hash表的realeSize,值取決于當前要做的是擴容還是收縮

擴容:則新的size是第一個 >= dict.ht[0].used + 1 的 2^n

刪除:則新的size是第一個 >= dict.ht[0].used 的 2^n (不小于 4)

2.按照新的realeSize申請內存空間,創建dictht,并賦值給dict.ht[1]

3.設置dict.rehashidx = 0,標識開始rehash

4.將dict.ht[0]的每個dictEntry都rehash到dict.h1

5.將dict.ht[1]的值賦給dict.ht[0] ,給dict.ht[1]初始化為 空哈希表,釋放原來的dict.ht[0]的內存。

rehash不是一次能夠完成的,如果數據百萬entry則需要分批次完成,否則可能導致線程阻塞

所以叫漸進式rehash

1.重新計算hash表的realeSize,值取決于當前要做的是擴容還是收縮

擴容:則新的size是第一個 >= dict.ht[0].used + 1 的 2^n

刪除:則新的size是第一個 >= dict.ht[0].used 的 2^n (不小于 4)

2.按照新的realeSize申請內存空間,創建dictht,并賦值給dict.ht[1]

3.設置dict.rehashidx = 0,標識開始rehash

4.將dict.ht[0]的每個dictEntry都rehash到dict.h1

5.每次增刪查改都檢查dict.rehashidx是否 > -1,如果是則將dict.ht[0].table[rehashidx]的entry鏈表rehash到dict.ht[1],并且將rehashidx++,直到所有數據都rehsh到dict.ht[1]

6.將dict.ht[1]的值賦給dict.ht[0] ,給dict.ht[1]初始化為 空哈希表,釋放原來的dict.ht[0]的內存。

7.rehashidx賦值-1,代表rehash結束

8.在rehash過程中,新增操作,則直接寫入ht[1],查詢、修改和刪除則會在dict.ht[0]和dict.ht[1]依次查找并執行。這樣可以確保ht[0]的數據只減不增,隨著rehash最終為空

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/903054.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/903054.shtml
英文地址,請注明出處:http://en.pswp.cn/news/903054.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Maven的聚合工程與繼承

目錄 一、為什么需要使用Maven工程 二、聚合工程的結構 三、聚合工程實現步驟 四、父工程統一管理版本 五、編譯打包 大家好&#xff0c;我是jstart千語。想著平時開發項目似乎都是用maven來管理的&#xff0c;并且大多都是聚合工程。而且在maven的聚合工程中&#xff0c…

前端職業發展:如何規劃前端工程師的成長路徑?

前端職業發展:如何規劃前端工程師的成長路徑? 大家好,我是全棧老李。今天咱們聊聊前端工程師的職業發展路徑,這個話題看似簡單,實則暗藏玄機。就像打游戲升級一樣,你得知道下一關是什么,才能提前準備裝備和技能點。 前端之路 一般我們從一個新手到大神,普遍需要經過…

【星海出品】分布式存儲數據庫etcd

etcd 數據庫由 CoreOS 公司創建。 https://github.com/etcd-io/etcd api信息 https://etcd.io/docs/v3.5/dev-guide/api_reference_v3/ etcdctl --help etcd 最初由 CoreOS 公司開發&#xff0c;作為其核心項目之一。 CoreOS 成立于 2013 年&#xff0c;專注于容器化技術&#…

2025新版修復蛇年運勢測試風水起名系統源碼

2025新版修復蛇年運勢測試風水起名系統源碼 通過網盤分享的文件&#xff1a;2025xbfsysweb.rar 鏈接: https://pan.baidu.com/s/1r1MOkJJJMj9s9nQX_GzI3Q 提取碼: 9weh 備用下載地址&#xff1a;http://pan.1234f.com:5212/s/JK1uw

Vue3 Pinia

一、Pinia 核心概念 Pinia 是 Vue3 官方推薦的狀態管理庫&#xff0c;相比 Vuex 4&#xff0c;具有以下優勢&#xff1a; 更簡潔的 API&#xff08;移除 mutations&#xff09; 完整的 TypeScript 支持 支持組合式 API 自動代碼分割 輕量級&#xff08;僅 1KB&#xff09;…

音視頻小白系統入門課-4

本系列筆記為博主學習李超老師課程的課堂筆記&#xff0c;僅供參閱 往期課程筆記傳送門&#xff1a; 音視頻小白系統入門筆記-0音視頻小白系統入門筆記-1音視頻小白系統入門筆記-2音視頻小白系統入門筆記-3 將mp4文件轉換為yuv文件 ffmpeg -i demo.mp4 # 輸入文件-an …

6.2 內容生成與營銷:個性化內容創作與營銷策略優化

隨著消費者對個性化體驗的需求日益增長&#xff0c;傳統的內容創作與營銷方式已難以滿足市場競爭的需要。基于大語言模型&#xff08;LLM&#xff09;與智能代理&#xff08;Agent&#xff09;的技術為企業提供了全新的解決方案&#xff0c;能夠實現高效、精準、規模化的內容生…

kafka課后總結

Kafka是由LinkedIn開發的分布式發布 - 訂閱消息系統&#xff0c;具備高吞吐量、低延遲、可擴展性、持久性、可靠性、容錯性和高并發等特性。其主要角色包括Broker、Topic、Partition、Producer、Consumer、Consumer Group、replica、leader、follower和controller。消息系統中存…

DataStreamAPI實踐原理——計算模型

引入 通過前面我們對于Flink的理解&#xff0c;我們知道它吸收了 Dataflow 的理念&#xff0c;以及此前已有的流處理系統&#xff08;如 S4、Storm、MillWheel&#xff09;的經驗&#xff0c;實現了批流一體化的高效數據處理&#xff0c;并且通過靈活的窗口機制、事件時間與水…

項目筆記1:通用 Service的常見方法

通用 Service 通常封裝了常見的業務邏輯操作&#xff0c;以提高代碼的復用性和可維護性。不同的框架和業務場景下&#xff0c;通用 Service 的方法會有所差異&#xff0c;但一般都會包含一些基本的增刪改查&#xff08;CRUD&#xff09;操作&#xff0c;以下為你詳細介紹&#…

阿里云99機器總是宕機,實測還是磁盤性能差

阿里云99計劃總是宕機&#xff0c;經過反復排查&#xff0c;最終確認還是磁盤性能差。 阿里云99機器使用的磁盤類型是Entry云盤40GiB (2120 IOPS) 按照官方的一些數據&#xff0c;這個磁盤最小iops是1800最大是6000,實際使用中發現&#xff0c;這個6000值很虛&#xff0c;這個…

Fedora 43 計劃移除所有 GNOME X11 相關軟件包

Fedora 43 計劃移除所有 GNOME X11 相關軟件包&#xff0c;這是 Fedora 項目團隊為全面擁抱 Wayland 所做的重要決策。以下是關于此計劃的詳細介紹&#xff1a; 提案內容&#xff1a;4 月 23 日&#xff0c;Neal Gompa 提交提案&#xff0c;建議從 Fedora 軟件倉庫中移除所有 G…

魔幻預言手游》:職業介紹!

在《魔幻預言》手游中&#xff0c;共有武玄、魔魅、劍仙三大核心職業&#xff0c;各具特色且定位鮮明&#xff0c;以下為具體介紹&#xff1a; 一、武玄&#xff08;戰士&#xff09; 核心定位&#xff1a;近戰物理輸出與團隊增益擔當&#xff0c;兼具控制與防御能力。 戰斗風…

精益數據分析(27/126):剖析用戶價值與商業模式拼圖

精益數據分析&#xff08;27/126&#xff09;&#xff1a;剖析用戶價值與商業模式拼圖 在創業和數據分析的領域中&#xff0c;每一次深入學習都是一次成長的契機。今天&#xff0c;我們繼續秉持共同進步的理念&#xff0c;深入研讀《精益數據分析》&#xff0c;剖析用戶價值的…

【SwitchyOmega安裝教程】

目錄 一、插件安裝 1. 下載安裝文件 2. 打開瀏覽器擴展安裝頁面 3. 安裝插件 二、界面詳情 三、配置信息 3.1 設置IP 1、查看IP地址信息 2、批量測試IP是否有效 3、點擊擴展程序&#xff0c;選擇 Proxy SwitchyOmega 4、 點擊選項進行配置 5、配置頁面 一、插件安裝 1…

矯平機終極指南:特殊材料處理、工藝鏈協同與全球供應鏈管理

一、特殊材料矯平&#xff1a;挑戰與創新解決方案 1. 高溫合金&#xff08;如Inconel 718&#xff09;處理 技術難點&#xff1a; 屈服強度高達1100 MPa&#xff0c;傳統矯平力不足 高溫下易氧化&#xff0c;需惰性氣體保護環境 解決方案&#xff1a; 采用雙伺服電機驅動&a…

反事實——AI與思維模型【82】

一、定義 反事實思維模型是一種心理認知模型,它指的是人們在頭腦中對已經發生的事件進行否定,然后構建出一種可能性假設的思維活動。簡單來說,就是思考“如果當時……,那么就會……”的情景。這種思維方式讓我們能夠超越現實的限制,設想不同的可能性和結果,從而對過去的…

Nginx:支持 HTTPS

文章目錄 Nginx 開啟 ssl 以支持 HTTPS1 生成本地證書2 開啟 ssl 以支持 HTTPS3 將 https 的請求轉發給 http 最終的 nginx.conf 如下 Nginx 開啟 ssl 以支持 HTTPS [!IMPORTANT] 在下文中&#xff0c;將采用如下定義。 HTTP端口&#xff1a; 80 HTTPS端口&#xff1a; 443 服務…

[計算機科學#2]:從繼電器到晶體管的電子計算機發展史(龐然大物的進化)

【核知坊】&#xff1a;釋放青春想象&#xff0c;碼動全新視野。 我們希望使用精簡的信息傳達知識的骨架&#xff0c;啟發創造者開啟創造之路&#xff01;&#xff01;&#xff01; 內容摘要&#xff1a;本文講述了20世紀初至1950年代計算機技術的發展歷程…

【ESP32S3】Cache 框圖和操作

ESP32-S3 采用雙核共享 ICache (指令緩存) 和 DCache &#xff08;數據緩存&#xff09; 結構&#xff0c;如下圖所示。以便當 CPU 的指令總線和數據總線同時發起請求時&#xff0c;也可以迅速響應&#xff1a; Cache 的存儲空間與內部存儲空間可以復用。具體為 Internal SRAM0…