上文我們講述了Redis的數據類型,以及應用場景,文章連結是《每個程式設計師都應該知道的Redis知識》。本文將講述如下內容:
Redis中Srting類型的底層實現原理通過String底層實現原理的學習,我們可以學習到哪些底層優化方法Redis中關於String命令介紹
我們知道Redis是由C語言實現的,在介紹Sring類型的實現之前我們先複習一下C語言的字符串類型。C語言中的字符串是以空字符結尾的字符數組,詳細說明見下圖:
01Redis中Srting類型的底層實現原理
Redis中沒有直接使用C語言的字符串,而是構建了一套自己的抽象類型,名為簡單動態字符串,簡稱SDS。
如果你看Redis源碼會發現這樣一種結構體:
len 記錄buf數組中已經使用字節的數量,也就是SDS類型所保存的字符串的長度。free 記錄了buf數組中未使用的字節數量buf 是存儲字節的數組,用於保存字符串從上面的結構我們可以看出:
Redis的String類型封裝成SDS結構,體現了用空間換時間的算法思想。犧牲了一些空間,來換取更快的查詢效率。比如說結構體中len的值5表示這個SDS保存了一個五個字節長的字符串,O(1)的時間複雜度就可以查詢出結果。Redis的定位就是資料庫層之上的一層緩存層,所以處處都要考慮高效。其實緩存本身也是用空間換時間思想的體現。解決了C字符串容易緩衝區溢出的問題。因為C字符串不記錄字符串長度,所以通過C語言的 strcat 函數拼接字符串的時候,容易造成拼接後的字符串超過了本身申請的字符串的長度,造成緩衝區溢出。SDS就不會出現這個問題空間預分配:在申請空間的時候預先分配好一定長度的空間。當空間不夠用的時候,通過SDS提供的API可以重新申請一片更大的空間。惰性釋放空間:當申請的空間不再被使用的時候,不是立刻釋放空間,而是在SDS中的free屬性將這些字節的數量記錄下來,等待將來使用二進位安全:封裝後的SDS解決了二進位安全問題,所以在Redis的String類型中可以緩存各種類型數據。SDS的API會以處理二進位的方式來處理SDS存放在buf數組裡的數據,不會對其中的數據做任何限制、過濾、或假設,數據在寫入時是什麼樣的,它被讀取時就是什麼樣的。
總結一下上面所說的,主要是兩個核心思想。第一是SDS這種結構的實現;第二是空間換時間的思想。後面也會有文章專門介紹空間換時間、時間換空間兩種思想的具體應用。
02底層優化方法學習
從上面的介紹我們可以學習到哪些底層優化方法呢?上文反覆提到用空間換時間思想,我想大多數開發人員在實際項目開發中都或多或少地使用過這種思想。Redis、Memcache的設計思路就是這種思想的具體體現。除了Redis,MySQL中也有大量運用,比如說索引就是其中之一。在作業系統、計算機體系結構設計中也存在大量這種設計。
除了空間換時間,內存預分配、惰性釋放也是很好的優化方法。比如說PHP-FPM進程管理方式中的動態方式(Dynamic),啟動的時候預先生成N個Worker進程,當訪問量增加時可以增加Worker進程的數量,當訪問量降下來後再銷毀掉或者保留這些增加的Worker進程,方面後面使用。
除了以上方法,還有很多值得學習和借鑑的方法,在此不再一一列舉。如果這篇文章對你有幫助,歡迎轉發給你的朋友,你們可以一起學習成長。如果有錯誤的地方或者表達不清晰的地方,也歡迎在評論區指出來。大家的支持就是我的動力,希望我們可以一起進步!
03
以下是Redis中String命令的介紹,可以結合前面講的原理來學習這些命令,一定會有不一樣的體會。