什麼是SDS
1.redis沒有直接使用C的字元串,而是自己實作了字元串的實作名叫SDS
2.c的字元串隻會用在值不會改變的地方,比如redislog列印
SDS的應用場景
1.
本地:0>set msg hellowrd
OK
鍵和值都是字元串對象,底層通過SDS實作
2.
本地:0>rpush fruits apple banana cherry
3
鍵是字元串對象 由SDS實作, 值是清單對象,清單對象包含三個字元串對象 分别由SDS實作
SDS結構定義
SDS遵循C的字元串定義,以空字元串()作為字元串的結尾,空字元串1位元組不計算在len裡面,好處就是直接使用C字元串的函數如:print(%,s-buf)
帶有未使用位元組數量的SDS
SDS和C字元串的差別
1. C字元結構是沒有記錄長度的,如果要擷取長度必須周遊字元,複雜度是0(N)
2.SDS是記錄了字元串長度擷取字元串長度是0(1)如:
本地:0>strlen msg
8
緩沖區溢出
因為C不記錄字元長度,如果在進行擴容時,隻能假定記憶體足夠,如果不足夠則會造成緩沖區溢出
擴容前 S1 和S2 2個字元緊鄰,我們要對S1進行擴容,因為沒有記錄長度我們并不知道記憶體是否足夠,執行:strcat(s1,"cluster")
擴容前:
擴容後
SDS如何解決緩沖區溢出
與C不同因為SDS記錄了未使用空間,在擴容前會先判斷空間是否足夠,如果不夠sdscat(redis SDS的拼接API)先擴容空間
如執行
strcat(s1,"cluster")
擴容前
擴容後
二進制安全
C的字元必須符合某種編碼(ASCII),并且除了字元串末尾之外字元串裡面不能包含空字元,否則會誤認為字元串結尾,這些使得C隻能儲存文本而不能儲存圖檔、視訊、音頻、壓縮檔案這樣的二進制資料
因為SDS并沒有使用空字元()判斷字元的結尾而是len來判斷,使用SDS可以儲存圖檔 視訊 音頻等二進制資料
SDS對于擴容的優化
空間預配置設定
當我們對SDS空間進行擴充的時候,SDS除了配置設定必要的空間,還會為SDS配置設定額外的未使用空間 free記錄。
公式:
1.如果對SDS進行修改後,len長度小于1M則配置設定len同樣大小的未使用空間 len+free+1為目前SDS占用空間 1為結尾空字元占用空間
2.如果對SDS進行修改有len長度大于1M則會額外配置設定1M未使用空間 len+1m+1為目前SDS占用空間 1為結尾空字元占用空間
當每次擴充SDS API都會檢查free是否有足夠空間,如果有則不執行擴充 直接使用 減少了配置設定次數,
通過空間預配置設定優化,将連續增長N次字元串需要擴充N次,變為最多N次
惰性配置設定
當SDS縮短字元長度時候,并不會完全釋放,隻是将多出來的空間記錄到free
如果移除字元串中所有的 x和y
移除前
移除後
将來需要拼接字元時則可以減少擴容
預配置設定和惰性配置設定空間浪費解決方式
通過上面的意思,會讓我們覺得會浪費空間,其實SDS也提供了API讓我們可以真正的釋放SDS未使用空間,是以不用擔心預配置設定和惰性配置設定造成的浪費
SDS的優點
1.比起C字元串,SDS擷取字元串長度是O(1)
2.比起C字元串,不會緩沖區溢出
3.減少字元串擴容時的配置設定次數
4.二進制安全
5.相容C字元串,可以重用C字元串的函數庫