Redis實現源碼-字符串基礎數據類型分析

        Redis並沒有直接使用C語言中的字符串類型,而是自己設計了一種數據結構,在Redis中,C語言中的字符串只使用在一些字符串值不會發生修改的地方,比如打印日誌。它爲什麼要這樣做?這樣做的好處是什麼呢?讓我們先來了解一下這種被稱爲Simple dynamic string(SDS)簡單動態字符的結構。

                                               
        SDS遵循了C字符串以空字符結尾的管理,保存空字符的1字節空間不計算在SDS的len屬性裏面,並且爲空字符分配額外的1字節空間,已經添加空字符到末尾等操作都是自動完成的。爲什麼要這麼做?這樣做的好處是SDS可以直接重用一部分C字符串函數庫裏面的函數。
    

leg: print("%s",s->buf); 

        回到剛纔的問題,探究SDS存在的意義以及給我們帶來的便捷:
        1.常熟複雜度獲取字符串長度  C字符串並不記錄自身的長度信息,所以爲了獲取一個C字符串的長度,程序必須遍歷整個字符串進行累加,複雜度爲O(N),而SDS在len屬性中記錄了SDS本身的長度,獲取長度複雜度僅爲O(1)。
        2.杜絕緩衝區溢出  除了獲取字符串的複雜度高之外,C字符串不記錄自身長度帶來的另一個問題是容易造成緩衝區溢出(buffer overflow)。當字符串修改時,SDS會先檢查空間是否滿足所需的要求,如果不滿足的話,會將SDS的空間擴展至執行修改所需的大小,所以SDS不需要手動修改SDS的空間大小。
         3.減少修改字符串帶來的內存重分配次數  C字符串每次增減或者縮短一個字符,程序都要對保存這個C字符串的數組進行一次內存分配操作:
        *如果是字符串增長操作,每次增加1個字節,N次操作就N次內存重分配,Nginx作爲一個高性能的數據庫,數據被修改較頻繁,在這樣的情況下,僅執行內存重分配就會佔用一小部分的時間,如果修改頻繁的話,可能會對性能造成影響。 SDS通過空間預分配和惰性空間釋放來減少內存重分配所需的總時間。 若字符串修改後大小小於1M,則系統多分配一倍的空間。leg:修改後25個字節  則buf數組長度爲 25+25+1("/0")=51.若大於1M,至多分配1M。 通過這種策略,內存重分配的次數由必定N次降爲最多N次。
        *字符串長度縮小時,空出的空間並不會立刻回收。
二進制安全
       經常說Redis是二進制安全的,這是什麼意思?是指其他類型的數據存儲進去,取出來內容就變了麼?這個理解也對,也不對。首先C語言中的字符串只能存儲文本文件,對一下圖片、文件不能存儲,這是爲什麼呢?“/0”空字符是C語言用來表示字符串的結尾,但同樣以爲着你的字符串中不能存在空字符,否則你的數據信息就會提前結束,也就是說,你存進去的跟你取出來的數據不一樣。Redis中的SDS對每個字符都是平等的,不會對任何字符進行替換、過濾等特殊處理。那麼問題來了,既然SDS中的buf數組跟C的字符串不一樣,那麼它依靠什麼判斷字符的結束? 還記得麼?Simple dynamic string的數據結構中有一個len屬性,存放着buf數組中實際的數據長度,這便是SDS的判斷依靠。

       不看不知道,一看嚇一跳。平常在使用Redis的String類型的時候總覺得會是一個簡單的String類型,誰知道底層做了這麼多小而美的細節處理,這種設計思想纔是我們最應該學習的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章