Redis的String數據類型底層實現

redis就是用c語言寫,但redis的string并沒有直接用c語言的string,而是自己搞了一個 SDS 結構體來表示字符串。
SDS 的全稱是 Simple Dynamic String,中文叫做“簡單動態字符串”。
想知道為什么這么做,我們先看看c語言的string是什么樣的。

C語言的string

  • 本質:是 char 類型的一維數組。
  • 結尾:必須以 \0 結束,表示字符串終止。
  • 長度判斷:靠遍歷字符直到 \0 來判斷長度。
c語言的string存在著以下缺點,并且也是redis不使用其的原因:
  • 判斷長度時不方便:
    • 通過遍歷到末尾的空格進行判斷,復雜度為O(n)
  • 擴容時不方便:
    • 因為沒有預分配的內存,所以每次追加數據時就得重新申請一塊內存空間,十分消耗資源。并且在C語言中需要程序員手動分配內存進行擴容,若操作不當可能發生內存溢出。
  • 特殊數據無法處理(二進制安全):
    • 因為末尾時以結束符結尾,那么我實際要存儲的數據如果末尾也是結束符,兩個空格末尾就會發生沖突。而二進制數據中會很經常出現結束符,所以叫作二進制安全。
這些缺點不符合redis的高性能,為了避免這些缺點,redis自己搞了一個 SDS 結構體來表示字符串。

redis中的string

當你 set abc abcdefg 時,這個 set 命令會創建出兩個 sds,一個存 key:abc,一個存 value:abcdefg。
key 和 value 在 redisDb 的 dict 中通過鍵值對哈希表進行映射。
sds結構如下:
struct attribute ((packed)) sdshdr8 {uint8_t len;        // 字符串長度,不包含結束標示uint8_t alloc;      // 分配空間unsigned char flags; // SDS類型char buf[];         // 字符數組(實際數據)
};
len字段的作用:
維護buf[]數組的長度,用于快速O(1)獲取字符串的長度(因為字符串內容實際上存儲在數組里,字符串長度等價于數組長度)。
若沒有len字段維護的長度,當我們每次要獲取字符串長度時,都需要從頭到尾遍歷得到O(n)。
alloc字段的作用:
alloc 表示預分配的內存,也就是為了容納新增元素而預留的空間。
想象一下,若沒有預分配的內存,每次新增元素時,數組會因為空間不足,去重新申請一塊內存空間,十分消耗資源。
有了預分配內存后,若當前剩余的預分配內存足夠容納新增元素時,我們就不需要再去分配內存空間,這樣可以大幅度減少內存分配次數,提高性能。
flags字段的作用:
表示?type(4位)?和 encoding(4位) 兩個字段,加起來 8 位,用位域實現。
其中 type 表示對象的邏輯類型,例如 string、list、set 等。這里的 type 是 string;encoding 表示對象的底層編碼方式,比如 int、embstr、raw 等。
buf[]字段的作用:
用于存儲字符串實際內容。

擴容策略

當你要“寫入數據”導致 len + 新增數據長度 > alloc 時,就會觸發擴容機制。

惰性空間釋放

當sds的字符串縮短了,sds的buf內會多出來一些空間,這個空間并不會馬上被回收,而是暫時留著以防再用的時候進行多余的內存分配。這個是惰性空間釋放的策略

SDS的優勢:

優化獲取字符串長度:

C語言要想獲取字符串長度必須遍歷整個字符串的每一個字符,然后自增做累加,時間復雜度為O(n);sds直接維護了一個len變量,時間復雜度為O(1)。

減少內存分配:

當我們對一個字符串類型進行追加的時候,可能會發生兩種情況:
  • 當前剩余空間(剩余空間 = alloc - len)足夠容納追加內容時,我們就不需要再去分配內存空間,這樣可以減少內存分配次數。
  • 當前剩余空間不足以容納追加內容,我們需要重新為其申請內存空間。

惰性釋放空間

當你對一個 Redis 字符串執行縮短操作(比如刪掉部分字符)時,Redis 只更新 len 字段,而不會立刻縮小 alloc 所占的內存,多余的空間會被保留,等待將來復用,這樣就避免了頻繁的內存申請
(如果你依舊想釋放多余空間,Redis 提供了手動釋放函數供調用。)
上面的SDS只是字符串類型中存儲字符串內容的結構,Redis中的字符串分為兩種存儲方式,分別是embstr和raw。

String的三種編碼格式(encoding)

String 在 Redis 中有三種編碼方式: int、embstr、raw 。
其中 raw 和 embstr 類型,都是基于動態字符串(SDS)實現的。
embstr
果存儲在 SDS 中的數據小于等于 44 字節,則會采用 EMBSTR 編碼,此時 RedisObject 與 SDS 是一段連續空間。而不是像 RAW 的編碼方式一樣,由 ptr 指向另外一片空間,申請內存時只需要調用一次內存分配函數,效率更高。
raw
raw 是 string 的基本編碼方式,基于簡單動態字符串(SDS)實現,存儲上限為512mb。當一個字符串采用 raw 的編碼方式的時候,它的結構如圖所示。
embstr的存儲方式是將RedisObject對象頭和SDS結構放在內存中連續的空間位置,也就是使用malloc方法一次分配,而raw需要兩次malloc,分別分配對象頭和SDS的空間。釋放空間也一樣,embstr釋放一次,raw釋放兩次,所以embstr是一種優化,
(malloc函數用于申請內存空間)
int
如果存儲的字符串是整數值,并且大小在 LONG MAX 范圍內,則會采用 INT 編碼。將字符串內容轉為 long,redisObject的對象 ptr 指向該long,并將 encoding 設置為 int,這樣就不需要重新開辟空間,算是長整形的一個優化。直接將數據保存在 RedisObject 的 ptr 指針位置(剛好8字節),不再需要SDS了。

為什么是44字節?

原因:對象頭占16字節,空的sdshdr占用4字節,也就是一個數據至少占用16+4=20字節。
其次操作系統使用jmalloc和tmalloc進行內存的分配,而內存分配的單位都是2的N次方,所以是 2,4,8,16,32,64 等字節,但是redis如果采取32的話,那么32-25=7,也太他媽少了,所以Redis采取的是64字節,所以:64-20=44。

盡量使用embstr和int編碼

在使用 string 類型時,盡可能讓其長度小于 44 字節,或者使用整數表示,使其使用 EMBSTR 和 INT 編碼。

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

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

相關文章

【音視頻學習】四、深入解析視頻技術中的YUV數據存儲方式:從原理到實踐

文章目錄 引言 1. YUV 基礎:為什么它比 RGB 更適合視頻? 1.1 YUV 與 RGB 的核心區別 1.2 YUV色度下采樣簡介 2. YUV 的三大存儲方式 方式一:平面格式(Planar) 方式二:半平面格式(Semi-Planar ) 方式三:打包格式(Packed YUV) 三種存儲方式對比: 3. 如何選擇合適的 Y…

前端項目組成

一、前端項目常見模塊及功能(以 Vue/React 通用結構為例) 前端項目的模塊本質是「按功能拆分的代碼文件/文件夾」,就像蓋房子的「磚、梁、窗」各司其職:模塊類型功能說明(大白話)舉個例子pages(…

聚觀早報 | 猿編程推動中美青少年AI實踐;華為Pura 80數字版售價公布;iPhone 17 Air電池曝光

聚觀早報每日整理最值得關注的行業重點事件,幫助大家及時了解最新行業動態,每日讀報,就讀聚觀365資訊簡報。整理丨肖羽7月24日消息猿編程推動中美青少年AI實踐華為Pura 80數字版售價公布iPhone 17 Air電池曝光亞馬遜收購AI初創公司Bee蜂巢半固…

unittest 案例執行順序詳解

unittest 案例執行順序詳解在 unittest 框架中,測試用例的執行順序有默認規則,也可通過自定義方式調整。以下是具體說明:一、默認執行順序規則unittest 對測試用例的執行順序遵循 “按測試方法名的 ASCII 碼排序” 原則,具體邏輯如…

【web大前端】001_前端開發入門:創建你的第一個網頁

前端開發入門:創建你的第一個網頁 在當今數字化時代,網頁已經成為人們獲取信息和交流的重要平臺。對于想要學習編程的人來說,前端開發往往是一個不錯的起點。本文將帶你通過簡單的兩步,創建屬于你的第一個網頁程序。 點擊這里去…

HTTP性能優化終極指南:從協議原理到企業級實踐

前言:為什么性能優化是Web開發的生命線?根據Google研究數據,當頁面加載時間從1秒增加到3秒時,跳出率提升32%;當達到5秒時,轉化率下降90%。本文將通過七層優化體系,帶您掌握HTTP性能優化的核心技…

Python 數據分析(二):Matplotlib 繪圖

目錄 1. 簡介2. 繪圖 2.1 折線圖 2.1.1 單線2.1.2 多線2.1.3 子圖 2.2 散點圖2.3 直方圖2.4 條形圖 2.4.1 縱置2.4.2 橫置2.4.3 多條 2.5 餅圖 1. 簡介 Matplotlib 是 Python 提供的一個繪圖庫,通過該庫我們可以很容易的繪制出折線圖、直方圖、散點圖、餅圖等豐…

Scrapy分布式爬蟲數據統計全棧方案:構建企業級監控分析系統

引言:數據統計在分布式爬蟲中的戰略價值在分布式爬蟲系統中,??數據統計與分析??是系統優化的核心驅動力。根據2023年爬蟲工程調查報告:實施專業統計方案的爬蟲系統性能提升??40%以上??數據驅動的優化策略可減少??70%??的資源浪費…

計劃任務(at和cron命令介紹及操作)

簡介計劃任務主要做一些周期性的任務,目前最主要的是定期備份數據分類at:一次性調度執行cron:循環調度執行at簡介at 是一個用于安排一次性任務的命令行工具,適合在指定時間點執行單次任務語法at 時間 選項若要提交,通過…

[2025CVPR:圖象合成、生成方向]WF-VAE:通過小波驅動的能量流增強視頻 VAE 的潛在視頻擴散模型

論文概述? 這篇論文提出了一種名為WF-VAE(Wavelet Flow VAE)?的新型視頻變分自編碼器(Video VAE),旨在解決潛在視頻擴散模型(LVDM)中的關鍵瓶頸問題,包括高計算成本和潛在空間不連續性。WF-VAE利用小波變換(Wavelet Transform)來分解視頻信號,并通過能量流路徑優…

Map接口-實現類HashMap

目錄 一、什么是Map? 二、實現類HashMap 1.關鍵特點 無序、key唯一、value允許重復、key和value允許為null。 2.數據結構 2.1 JDK 1.7 2.2 JDK 1.8 2.3 關鍵參數 2.4 關鍵計算 3.擴容方式 3.1 初始化 3.2 擴容 4.常見方法 4.1 根據key存入value 4.2 …

深入解析Hadoop如何實現數據可靠性:三副本策略、校驗和驗證與Pipeline復制

Hadoop數據可靠性的重要性在大數據時代,數據可靠性已成為企業數字化轉型的生命線。根據IDC預測,到2025年全球數據總量將增長至175ZB,其中企業數據占比超過60%。面對如此龐大的數據規模,任何數據丟失或損壞都可能造成數百萬美元的經…

15.6 DeepSpeed+Transformers實戰:LLaMA-7B訓練效率提升210%,顯存直降73%

DeepSpeedTransformers實戰:LLaMA-7B訓練效率提升210%的底層邏輯與實操指南 當LLaMA-7B的訓練顯存需求達到78GB時,單卡A100(80GB)幾乎瀕臨溢出,更不用說普通GPU集群。而DeepSpeed與Hugging Face Transformers的深度集成,通過"ZeRO三階段優化+混合精度+梯度檢查點&q…

Nginx + PM2 實現Express API + React 前端 本地測試服務器搭建

一、工具準備 openSSL:需要針對https請求頭 生成對應的 自簽名證書。 Nginx:服務器搭建工具 nodeJS: Express API運行環境 PM2: node進程管理器。用于替代npm命令管理 啟動命令。 二、openSSL 本地自簽名證書生成。 創建服務器空文件夾&#xff08…

OTG原理講解

文章目錄一、什么是 OTG(USB On-The-Go)?? OTG 的定義:二、傳統 USB 與 OTG 的區別三、OTG 的核心機制:**通過 ID 引腳判斷角色**1. 對于 Micro-USB OTG:2. 電路如何感知 ID 引腳?四、OTG 電路…

數據結構系列之紅黑樹

前言 紅黑樹是比較重要的一顆樹了,map和set的底層就是紅黑樹,一定要牢牢記住。 一、什么是紅黑樹 首先:紅黑樹仍然是一顆搜索二叉樹,但他引入了顏色這一概念,每個結點多一個存儲位來存儲顏色,它通過維護下…

在OpenMP中,#pragma omp的使用

在OpenMP中,#pragma omp for 和 #pragma omp parallel for(或 #pragma omp parallel num_threads(N))有本質區別,主要體現在 并行區域的創建 和 工作分配方式 上。以下是詳細對比:1. #pragma omp for 作用 僅分配循環迭…

停止“玩具式”試探:深入拆解ChatGPT Agent的技術棧與實戰避坑指南

摘要: 當許多人還在用ChatGPT寫周報、生成樣板代碼時,其底層的Agent化能力已經預示著一場深刻的開發范式變革。這不再是簡單的“AI輔助”,而是“人機協同”的雛形。本文旨在穿透表面的功能宣傳,從技術棧層面拆解Agent模式的實現基…

element-plus安裝以及使用

element-plus時為vue.js 3開發的組件庫。 在引入前需要做如下準備 安裝node.js https://blog.csdn.net/zlpzlpzyd/article/details/147704723 安裝vue的腳手架vue-cli https://blog.csdn.net/zlpzlpzyd/article/details/149647351 安裝element-plus github地址 https://git…

學習隨想錄-- web3學習入門計劃

#60 轉方向 web3 golang 以太坊應用 這是課表部分(Golang以太坊方向) Sheet b站up學習計劃 第一階段:基礎能力構建(1-2 個月) 學習目標 掌握 Golang 核心語法與以太坊底層基礎概念,建立開發知識框架。…