6、Redis系統-數據結構-01-String

Redis 數據結構簡介

前言

Redis 是一個高性能的內存數據庫,其關鍵在于其數據結構的設計。Redis 數據結構是指底層實現 Redis 鍵值對中值的數據類型的方式。它包括了以下幾種主要對象:

  1. String(字符串)對象:最基本的數據類型,可以存儲任意類型的數據,包括字符串、整數、浮點數等。
  2. List(列表)對象:一個鏈表,可以按順序存儲多個字符串,支持從兩端進行操作。
  3. Hash(哈希)對象:用于存儲鍵值對集合,類似于一個小型的鍵值對數據庫。
  4. Set(集合)對象:一個無序集合,自動去重,支持集合操作如交集、并集等。
  5. Zset(有序集合)對象:類似于 Set,但每個元素都會關聯一個權重(score),元素按權重排序。

????????隨著 Redis 版本的更新,這些數據類型的底層數據結構也有所不同,如雙向鏈表、壓縮列表、哈希表、跳表、整數集合、quicklist 和 listpack 等。這些數據結構的選擇使得 Redis 在處理數據的增刪查改操作時能夠高效地運行。

????????研究 Redis 的底層數據結構有助于我們深入理解 Redis 的工作原理,優化性能,確保數據的安全性,擴展系統的能力,并更好地排查和解決問題。這對于使用和管理 Redis 數據庫以及構建高效可靠的應用程序都是非常有價值的。本文將詳細介紹 Redis 的底層數據結構。

一、SDS(Simple Dynamic String,簡單動態字符串)

1、SDS的必要性
  1. C 語言字符串的限制

    • 字符數組表示:在 C 語言中,字符串是以字符數組(char*)的形式表示,以\0字符作為結尾標記。
    • 長度計算復雜度高:字符串長度的獲取需要遍歷整個字符數組,時間復雜度為 O(N)。
    • 無法保存二進制數據:由于\0字符標記字符串結束,字符串中不能包含\0字符,因此無法保存二進制數據。
    • 安全性問題:C 語言標準庫中的字符串操作函數如?strcat?存在緩沖區溢出等安全性問題,因為它們不檢查緩沖區大小是否足夠。
  2. Redis 的需求

    • 高效操作:需要高效獲取字符串長度和修改字符串的能力。
    • 二進制安全:需要能夠存儲和操作二進制數據。
    • 安全性:需要安全的字符串操作,避免緩沖區溢出等問題。

為了克服 C 語言字符串的不足,Redis 采用了 SDS 作為其字符串數據類型的底層數據結構。

2、SDS的數據結構

SDS 的數據結構如下:

struct?sdshdr?{int?len;???????// 記錄了字符串的長度int?free;??????// 分配給字符數組的剩余空間長度char?buf[];????// 字符數組,用來保存實際數據
};

結構中的每個成員變量分別介紹如下:

  • len:記錄了字符串長度。這樣在獲取字符串長度時,只需要返回這個成員變量值即可,時間復雜度為 O(1)。
  • alloc:分配給字符數組的剩余空間長度。在修改字符串時,可以通過?alloc - len?計算出剩余的空間大小,用于判斷是否需要擴展空間。
  • buf[]:字符數組,用來保存實際數據。不僅可以保存字符串,也可以保存二進制數據。

總的來說,Redis 的 SDS 結構在原本字符數組之上,增加了三個元數據:lenfreeflags,用來解決 C 語言字符串的缺陷。

3、SDS的優勢
  1. O(1) 復雜度獲取字符串長度

    • C 語言的?strlen?函數需要遍歷字符串,時間復雜度為 O(N)。
    • SDS 通過?len?成員變量直接返回字符串長度,時間復雜度為 O(1)。
  2. 二進制安全

    • SDS 不需要?\0?字符標識字符串結尾,而是通過?len?成員變量記錄長度,可以存儲包含?\0?的數據。
    • 為了兼容部分 C 語言標準庫函數,SDS 字符串結尾仍會加上?\0?字符。
    • SDS 的 API 處理數據時以二進制方式處理,程序不會對數據做任何限制,保證數據的原樣讀取和寫入。
  3. 避免緩沖區溢出

    • C 語言字符串操作函數如?strcat?把緩沖區大小是否滿足操作需求的檢查交給開發者,存在緩沖區溢出的風險。
    • SDS 通過?alloc?和?len?成員變量,在進行字符串修改時由程序內部判斷緩沖區大小是否足夠。
    • 當緩沖區大小不夠用時,Redis 會自動擴展 SDS 的空間大小,滿足修改所需的空間。

    SDS 的擴容規則如下:

    • 如果所需的 SDS 長度小于 1 MB,擴容按翻倍進行,即 2 倍的?newlen
    • 如果所需的 SDS 長度超過 1 MB,擴容長度為?newlen + 1MB
  4. 節省空間

    • SDS 設計了 5 種類型的結構體(sdshdr5sdshdr8sdshdr16sdshdr32sdshdr64),根據?len?和?alloc?成員變量的數據類型不同來適應不同大小字符串的存儲需求。
    • 不同的數據類型限制了字符數組長度和分配空間大小的上限,從而有效地節省內存空間。
4、SDS 數據結構的實現

以下是 SDS 的實現示例,包括創建、釋放、拼接和復制操作:

  1. 創建 SDS

    sds?sdsnew(const?char?*init)?{size_t?initlen = (init ==?NULL) ??0?:?strlen(init);sds s = sdsnewlen(init, initlen);return?s;
    }
    
  2. 釋放 SDS

    void?sdsfree(sds s)?{if?(s ==?NULL)?return;zfree((char*)s -?sizeof(struct?sdshdr));
    }
    
  3. 拼接字符串

    sds?sdscat(sds s,?const?char?*t)?{return?sdscatlen(s, t,?strlen(t));
    }
    
  4. 復制字符串

    sds?sdscpy(sds s,?const?char?*t)?{return?sdscpylen(s, t,?strlen(t));
    }
    
  5. 獲取 SDS 長度

    size_t?sdslen(const?sds s)?{struct?sdshdr?*sh?=?(void*) (s - (sizeof(struct?sdshdr)));return?sh->len;
    }
    
  6. 清空 SDS

    void?sdsclear(sds s)?{struct?sdshdr?*sh?=?(void*) (s - (sizeof(struct?sdshdr)));sh->free?+= sh->len;sh->len =?0;s[0] =?'\0';
    }
    
5、整數類型存儲優化

在 Redis 中,如果字符串內容可以表示為數字類型,通常可以優化存儲為 long 類型或整數集合(intset)。這是因為整數類型的存儲和操作通常比字符串更高效。

  1. 使用整數類型存儲數字字符串

    • Redis 的字符串對象可以存儲整數類型的值。如果字符串可以被解析為整數,Redis 會將其轉換為整數類型進行存儲。例如,執行?SET key "12345"?時,Redis 會將其存儲為整數編碼(INT),而不是字符串編碼。
  2. 整數集合(intset)

    • 整數集合是一種緊湊的有序集合,適用于存儲小范圍的整數集合。它的內部結構如下:
    typedef?struct?intset?{uint32_t?encoding;?// 編碼類型(int16, int32, int64)uint32_t?length;???// 集合中元素的個數int8_t?contents[];?// 元素數組
    } intset;
    
結論

通過上述解析,我們可以更好地理解 SDS 的設計思想和實現原理,從而在實際開發中更好地利用 SDS 提供的優勢。在 Redis 中,字符串可以表示為數字類型時,會自動轉換為整數類型進行存儲,以提高存儲和操作效率。此外,Redis 提供了整數集合(intset)數據結構,用于高效存儲一組整數。了解這些優化策略

,可以幫助我們在實際應用中更好地利用 Redis 的性能和功能。

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

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

相關文章

[C++][CMake][流程控制]詳細講解

目錄 1.條件判斷1.基本表達式2.邏輯判斷3.比較4.文件操作5.其他 2.循環1.foreach2.while 1.條件判斷 在進行條件判斷的時候,如果有多個條件,那么可以寫多個elseif,最后一個條件可以使用else,但是開始和結束是必須要成對出現的&am…

WordPress常見問題及簡要說明

1. 如何安裝WordPress? 簡要說明:WordPress是一個流行的內容管理系統,可以幫助用戶快速搭建網站。安裝WordPress需要以下幾個步驟:下載WordPress安裝包、上傳到服務器、創建數據庫、配置數據庫信息、完成安裝。 2. 如何創建一個新的WordPr…

掌握電量脈搏:WebKit 電池狀態(Battery Status API)支持全解析

掌握電量脈搏:WebKit 電池狀態(Battery Status API)支持全解析 隨著移動設備的廣泛使用,Web 應用對設備的電池狀態信息的需求日益增長。Battery Status API 提供了一種方式,允許 Web 應用訪問設備的電池信息&#xff…

【反悔貪心 反悔堆】1642. 可以到達的最遠建筑

本文涉及知識點 反悔貪心 反悔堆 LeetCode1642. 可以到達的最遠建筑 給你一個整數數組 heights ,表示建筑物的高度。另有一些磚塊 bricks 和梯子 ladders 。 你從建筑物 0 開始旅程,不斷向后面的建筑物移動,期間可能會用到磚塊或梯子。 當…

Spring Boot中的全局異常處理

Spring Boot中的全局異常處理 大家好,我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編,也是冬天不穿秋褲,天冷也要風度的程序猿!今天我們將探討如何在Spring Boot應用中實現全局異常處理,這是保證應用…

VSCode, 請在windows下使用git bash終端

用vscode在windows下調測代碼,運行時默認打開的終端是windows的cmd,很不受我待見。畢竟習慣了linux,習慣了windows下的git bash風格。怎么辦? search,search,research。 先確保windows上安裝了git bash。…

MATLAB 2024b 更新了些什么?

MATLAB 2024b版本已經推出了預覽版,本期介紹一些MATLAB部分的主要的更新內容。 幫助瀏覽器被移除 在此前的版本,當我們從MATLAB中訪問幫助文檔時,默認會通過MATLAB的幫助瀏覽器(Help browser)。 2024b版本開始&…

【Unity數據交互】如何Unity中讀取Ecxel中的數據

👨?💻個人主頁:元宇宙-秩沅 👨?💻 hallo 歡迎 點贊👍 收藏? 留言📝 加關注?! 👨?💻 本文由 秩沅 原創 👨?💻 專欄交流🧧&…

醫院掛號系統小程序的設計

管理員賬戶功能包括:系統首頁,個人中心,患者管理,醫生管理,專家信息管理,科室管理,預約信息管理,系統管理 微信端賬號功能包括:系統首頁,專家信息&#xff0…

數據結構算法-排序(一)-冒泡排序

什么是冒泡排序 冒泡排序:在原數組中通過相鄰兩項元素的比較,交換而完成的排序算法。 算法核心 數組中相鄰兩項比較、交換。 算法復雜度 時間復雜度 實現一次排序找到最大值需要遍歷 n-1次(n為數組長度) 需要這樣的排序 n-1次。 需要 (n-1) * (n-1) —…

Java事務(Transaction)

Java事務(Transaction)是數據庫管理系統執行過程中的一個邏輯單位,由一個有限的數據庫操作序列組成,這些操作要么全部執行,要么全部不執行,是一個不可分割的工作單位。事務的引入主要是為了解決并發操作數據…

Unity中遇到“Input Button unload_long_back_btn is not setup”問題

當你在Unity中遇到“Input Button unload_long_back_btn is not setup”這個問題時,需要按照以下步驟進行處理: 1. 檢查按鈕名稱 確保你在代碼中使用的按鈕名稱(unload_long_back_btn)與Unity輸入管理器中的配置完全匹配。 2. …

[AIGC] ClickHouse分布式表與本地表的區別及如何查詢所有本地表記錄

在大規模數據處理和分析場景中,ClickHouse是一種高性能的列式數據庫管理系統。ClickHouse支持分布式表和本地表兩種表類型,本文將介紹這兩種表類型的區別,并探討如何建表以查詢所有本地表的記錄。 文章目錄 一、ClickHouse分布式表與本地表的…

【Linux進階】文件系統7——文件系統簡單操作

1.磁盤與目錄的容量 現在我們知道磁盤的整體數據是在超級區塊中,但是每個文件的容量則在inode 當中記載。 那在命令行模式下面該如何顯示這幾個數據?下面就讓我們來談一談這兩個命令: df:列出文件系統的整體磁盤使用量&#xf…

Poker Game, Run Fast

Poker Game, Run Fast 撲克&#xff1a;跑得快 分門別類&#xff1a; 單張從小到大默認 A < 2 < 3 < 4 < 5 < 6 < 7 < 8 < 9 < 10 < J < Q < K 跑得快&#xff1a;單張從小到大 3 < 4 < 5 < 6 < 7 < 8 < 9 < 10 &…

javaweb個人主頁設計(html+css+js)

目錄 1 前言和要求 1.1 前言 1.2 設計要求 2 預覽 2.1 主頁頁面 2.2 個人簡介 2.3 個人愛好 2.4 個人成績有代碼&#xff0c;但是圖片已省略&#xff0c;可以根據自己情況添加 2.5 收藏夾 3 代碼實現 3.1 主頁 3.2 個人簡介 3.3 個人愛好 3.4 個人成績&#xff…

大數據處理利器:Apache Spark編程基礎與實戰

"大數據處理利器&#xff1a;Apache Spark編程基礎與實戰" 是一個涵蓋了Apache Spark這一強大大數據處理框架的深入學習和實踐指南。Apache Spark是一個快速、通用、可擴展的大數據處理引擎&#xff0c;它提供了高級別的API用于大規模數據處理和分析。下面&#xff0…

求職成功率的算法,與葫蘆娃救爺爺的算法,有哪些相同與不同

1 本節概述 通過在B站百刷葫蘆娃這部兒時劇&#xff0c;我覺得可以從中梳理出一些算法&#xff0c;甚至可以用于求職這個場景。所以&#xff0c;大家可以隨便問我葫蘆娃的一些劇情和感悟&#xff0c;我都可以做一些回答。 2 葫蘆娃救爺爺有哪些算法可言&#xff1f; 我們知道…

身體(body)的覺醒

佛&#xff0c;是一個梵文的漢語音譯詞&#xff0c;指覺醒者。 何謂覺醒&#xff1f;什么的覺醒&#xff1f;其實很簡單&#xff0c;就是身體的覺醒。 佛的另一個名字&#xff0c;叫菩提&#xff0c;佛就是菩提&#xff0c;菩提老祖&#xff0c;就是佛祖。 body&#xff0c;即…

微服務: 初識 Spring Cloud

什么是微服務? 微服務就像把一個大公司拆成很多小部門&#xff0c;每個部門各自負責一塊業務。這樣一來&#xff0c;每個部門都可以獨立工作&#xff0c;即使一個部門出了問題&#xff0c;也不會影響整個公司運作。 什么是Spring Cloud? Spring Cloud 是一套工具包&#x…