Redis數據結構之簡單動態字符串SDS

Redis的底層數據結構非常多,其中包括SDS、ZipList、SkipList、LinkedList、HashTable、Intset等。如果你對Redis的理解還只停留在get、set的水平的話,是遠遠不足以應對面試提問的。本文簡單介紹了Redis底層最重要的數據結構 - 簡單動態字符串(SDS)

Redis使用C語言開發,但并沒有使用C語言傳統的字符串表示(以空字符結尾的字節數組,以下簡稱C字符串),而是自己構建了一種名為簡單動態字符串的(simple dynamic string,SDS)的抽象類型,并將SDS用作Redis的默認字符串表示。

在Redis里面,C字符串只會作為字符串字面量(static literal)用在一些無須對字符串值進行修改的地方。當Redis需要的不僅僅是一個字符串字面量,而是一個可以被修改的字符串值時,Redis就會使用SDS來表示字符串值,比如在Redis的數據庫里面,包含字符串的鍵值對在底層都是由SDS實現的。

咱們來舉個例子,如果在客戶端執行命令:

redis> SET msg "hello world"
ok

那么Redis將在數據庫中創建一個新的鍵值對,其中:

  • 鍵值對的鍵是一個字符串對象,對象的底層實現是一個保存著字符串“msg”的SDS。
  • 鍵值對的值也是一個字符串對象,對象的底層實現是一個保存著字符串“hello world”的SDS。

除了用來保存數據庫中的字符串值之外,SDS還被用作緩沖區:AOF模塊中的AOF緩沖區,以及客戶端狀態中的輸入緩沖區,都是由SDS實現的。總之,SDS是Redis的最基礎也是最重要的數據結構。

1.SDS的定義

每個 sds.h/sdshdr 結構表示一個SDS值:

struct sdshdr{// 記錄buf數組中已使用字節的數量// 等于SDS所保存字符串的長度int len;// 記錄buf數組中未使用字節的數量int free;//字節數組,用于保存字符串char buf[];
}

用一張圖來表示:

1136672-20190125181258686-2024120115.png

SDS 遵循 C 字符串以空字符結尾的慣例, 保存空字符的 1字節空間不計算在 SDS 的 len 屬性里面, 并且為空字符分配額外的 1 字節空間, 以及添加空字符到字符串末尾等操作都是由 SDS 函數自動完成的, 所以這個空字符對于 SDS 的使用者來說是完全透明的。

2.SDS與C字符串的區別

現在來說,C語言使用長度為N+1的字符數組來表示長度為N的字符串,并且字符數組的最后一個元素總是空字符“\0”。

C的這種簡單的字符串表達方式,并不能滿足Redis對字符串在安全性、效率以及功能方面的要求。具體有以下幾個方面。

2.1 常數復雜度獲取字符串長度

因為C字符串并不記錄字符串的長度信息,所以為了獲取一個C字符串的長度,程序必須遍歷整個字符串,對遇到的每個字符進行計數,直到遇到空字符為止,這個操作的復雜度為O(n)。而在Redis的SDS中,這個時間復雜度只有O(1)。

2.2 杜絕緩沖區溢出

除了獲取字符串長度的復雜度高之外,C字符不記錄自身長度帶來的另一個問題就是緩沖區溢出。舉個例子,C語言的 strcat 函數可以將字符串中的內容拼接到 dest 字符串的末尾,但是當字符串的容量不夠就會產生緩存區溢出,因為字符串也是基于數組實現的,也是有大小限制的。

Redis的SDS已經杜絕了這個問題,那它是如何解決的呢?

當API要對SDS進行修改時,API會先檢查SDS的空間是否滿足修改所需的空間,如果不夠的話,API會自動將SDS的空間進行擴容,然后才執行實際的修改操作。這就避免了緩沖區內存溢出。

2.3 減少修改字符串時帶來的內存重分配次數

上面說到了API會在修改SDS字符串時自動擴容,如果每次修改都伴隨著對字符串內的數組的內存重分配,那效率可想而知。所以Redis實現了空間預分配和惰性空間釋放兩種優化策略。

空間預分配

空間預分配用于優化SDS的字符串增長操作:當SDS的API對一個SDS進行修改,并且需要對SDS進行空間擴展的時候,程序不僅會為SDS分配修改所需要的空間,還會為SDS分配額外的未使用空間。

總的來說,額外分配的未使用空間數量大小有兩種可能:

  1. 如果對SDS修改之后,SDS的長度將小于1MB,那么程序分配和len 屬性同樣大小的未使用空間,這時候SDS的 free 屬性的值將和 len 屬性的值相同。也就是說,該SDS字符串修改完后還有近一半的容量。
  2. 如果對SDS修改之后,SDS的長度大于等于1MB,那么程序會分配1MB的未使用空間。這個是固定的。

通過空間預分配,Redis可以減少連續執行字符串操作所需的內存重分配次數。

惰性空間釋放

惰性空間釋放用于優化SDS的字符串縮短操作:當SDS的API需要縮短SDS保存的字符串時,程序并不立即使用內存重分配來回收縮短后多出來的字節,而是使用 free 屬性將這些字節的數量記錄起來,并等待將來使用。

2.4 二進制安全

在C語言中,字符串的存儲必須符合某種編碼(ASCII),并且字符串不能包含空字符,否則會被認為是字符串結尾。這些限制使得C字符串只能保存文本數據,而不能保存像圖片、音頻、視頻、壓縮文件這樣的二進制數據。

所以,為了解決C字符串的不足,Redis的 buf 數組保存的是二進制數據,這也就是把SDS的 buf 數組稱為字節數組的原因。

2.5 兼容部分C字符串函數

雖然 Redis 的API都是二進制安全的,但它們一樣遵循C字符串以空字符串結尾的慣例,這些API總會將SDS保存的數據的末尾設置為空字符,并且總會在為 buf 數組分配空間時多分配一個字節來容納這個空字符,這是為了讓那些保存文本數據的SDS可以重用一部分C的函數。

舉個例子, 如果我們有一個 SDS 的指針 s , 那么我們可以直接使用 stdio.h/printf 函數, 通過執行以下語句:

printf("%s", s->buf);

來打印出 SDS 保存的字符串值 "Redis" , 而無須為 SDS 編寫專門的打印函數。

最后,臨近春節,祝大家新年快樂!

轉載于:https://www.cnblogs.com/yueshutong/p/10335986.html

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

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

相關文章

Centos7 安裝OpenTSDB

Centos7 安裝OpenTSDB https://www.imzcy.cn/1697.html轉載于:https://www.cnblogs.com/RHadoop-Hive/p/10563385.html

職場潛規則冷思考:別讓老板“殺”了你

一位3年前共事過的同事走了,就在他以200多萬的房貸代價拿到大門鑰匙的時候,猝然倒在新房的樓梯上。另一個曾經在同一戰壕里沖鋒陷陣的同事被老板辭掉了,兢兢業業,起早貪黑,竟然沒有熬過35歲下崗這一關,這時…

Backtrader交易基礎2

成交價格確定: Order.Market 市價單,以當時市場價格成交的訂單,不需要自己設定價格。市價單能被快速達成交易,防止踏空,盡快止損/止盈; 按下一個 Bar (即生成訂單的那個交易日的下一個交易日&…

windows 小技巧

2019獨角獸企業重金招聘Python工程師標準>>> 桌面圖標顯示不全、圖標呈現白色方塊 ie4uinit -show 關閉占用指定端口的進程 獲取進程: netstat -ano | findstr 端口號關閉進程:taskkill -f -pid 進程號文件被占用 打開任務管理器,切換到 性能…

進一步了解 apt-get 的幾個命令

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 用 apt-get 也很久了,沒多想它的實現,最近遇到 gstreamer 裝不上的問題,才多看看了它 apt-get 就是…

java學習筆記20(Arraylist復習,Collection接口方法,迭代器,增強型for循環)

集合:集合是Java提供的一種容器,可以用來存儲多個數據; 集合與數組的區別:集合的長度是可變的,數組的長度是固定的 集合中存儲的數據必須是引用類型數據; ArrayList回顧: public class Person {…

backtrader數據基礎

cerebro bt.Cerebro() cerebro.addstrategy(TestStrategy2) codes[600862.SH,300326.SZ,300394.SZ] #加載最近兩日交易數據 for code in codes:feed Addmoredata(dataname get_data(code,20200506),namecode)cerebro.adddata(feed) cerebro.run() 數據查看: cl…

談判學:三招了解對方底線

導讀:談判者都希望能了解對方的底線,最直接的一招就是將對手變成“朋友”,只是這種“內奸法”畢竟不是常規之法。大多數情況下,談判雙方也不可能像《無間道》一樣在對方陣營安放臥底,但是我們完全可以通過一些辦法來揣…

JSLint檢測Javascript語法規范

前端javascript代碼編寫中,有一個不錯的工具叫JSLint,可以檢查代碼規范化,壓縮JS,CSS等,但是他的語法規范檢查個人覺得太“苛刻”了,會提示各種各樣的問題修改建議,有時候提示的信息我們看的莫名…

Apt 命令解說(apt-get update、apt-cache search package、apt-get install package、apt-get remove )

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 高級打包工具(英語:Advanced Packaging Tools,縮寫為APT)是Debian及其派生發行版的軟件包…

SQL SERVER 2012 AlwaysOn - 維護篇 03

搭建 AlwaysOn 是件非常繁瑣的工作,需要從兩方面考慮,操作系統層面和數據庫層面,AlwaysOn 非常依賴于操作系統,域控,群集,節點等概念; DBA 不但要熟悉數據庫也要熟悉操作系統的一些概念&#xf…

指標研究與多周期

哪些地方會用到指標 ? 回顧一下 Backtrader 的主要功能模塊和回測流程(見:Backtrader 來了!)可以發現,只有在編寫策略Strategy 時才會涉及到指標的計算和使用,而且是 Strategy 中的 __init__()…

區塊鏈BAAS平臺:公共或私人區塊鏈編程以用于各種用途

2019獨角獸企業重金招聘Python工程師標準>>> 人們可以為公共或私人區塊鏈編程以用于各種用途。理論上,我認為犧牲權力下放的方面可以解決區塊鏈技術背后的許多當前問題。區塊鏈仍然可以包容,而不是分散。這如何解決當前的一些問題&#xff1f…

CURL 是什么

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 cURL是一個利用URL語法在命令行下工作的文件傳輸工具,1997年首次發行。 它支持文件上傳和下載,所以是綜合傳輸工…

易用性問題回復

針對淘寶網為例,以一次完整的購物流程為背景,我們分析了在淘寶網中的一些易用性的體現,主要場景如下圖所示: 在本場景中,新用戶下載淘寶app時,第一次打開應用,淘寶app會出現新手指引,教會用戶如…

易盛極星期貨量化教學

我目前量化實盤做期貨交易用的是這個軟件。主要就是因為它可以做套利合約,還有就是國企的外包,安全(vnpy的狗咬狗害怕)。 策略模板: 設置全局參數變量: #導入包 import talib #選擇合約代碼 code1 #設…

eBay是如何進行大數據集元數據發現的

很多大數據系統每天都會收集數PB的數據。這類系統通常主要用于查詢給定時間范圍內的原始數據記錄,并使用了多個數據過濾器。但是,要發現或識別存在于這些大型數據集中的唯一屬性可能很困難。 在大型數據集上執行運行時聚合(例如應用程序在特定…

職業發展 先“立功”還是先“安內”?

導讀:職業生涯更上一層樓,章良躊躇滿志,想在短期內建功立業,奠定江湖地位。但他清楚,自己運籌中的分公司服務升級計劃,對公司整體和自己的職業生涯都非常有利,卻將不可避免地轉移老將掌握的部分…

網關 Kong 折騰筆記 - 相關技術清單

背景 前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 公司準備更好的實現微服務架構,我前期的任務主要是 API 開發相關的技術學習,微服務會隨著業務的增加不斷增加…

Quantaxis更新數據到最新

登錄QQ群:563280067 安裝方法: 1.進入命令界面, 2.pip install pytdx-1.72r2-py3-none-any.whl 3. pip install quantaxis-1.10.19r1-py3-none-any.whl 之后輸入save save all 即可看到所有的數據全部安裝到位