翻這本書已經不止一次了,可是老是學完就忘,藉着此次部門組織興趣小組再從新系統的學習一遍。但當我和同事討論這本書學來有什麼用的時候,你們都有點兩眼一抹黑,我自問本身也有點迷茫。「是啊,我看過了,而後我也不知道這個有什麼用「。因此我就google了一下」SDS的好處「。html
像咱們平時用的都是從使用者的角度。好比:string、list、hash、set、sorted set。redis
從內部實現的角度。好比:dict、sds、ziplist、quicklist、skiplist數組
我恍然大悟,我明白了redis是如何用內部的數據結構去實現經常使用的數據結構。這樣我就能明白這本書所表達的含義了。安全
在討論任何一個系統的內部實現的時候,咱們都要先明確它的設計原則,這樣咱們才能更深入地理解它爲何會進行如此設計的真正意圖。在本文接下來的討論中,咱們主要關注如下幾點:bash
Redis本身構建了一個數據結構 命名爲 簡單動態字符串(simple dynamic string,SDS)網絡
struct sdshdr {
//記錄buf數組中已使用字節的數量 等於SDS所保存字符串的長度
int len;
//記錄buf數組中未使用字節的數量
int free;
//字節數組,用戶保存字符串
char buf[];
}複製代碼
SDS遵循C字符串以空字符串結尾的慣例,好處是能夠直接重用一部分C字符串函數庫裏面的函數。可是C字符串不知足Redis對字符串在安全性、效率以及功能方面的要求。數據結構
C字符串自己不記錄自身的長度信息,獲取長度信息時,須要遍歷整個字符串進行計數,直到遇到字符串結尾的空字符串爲止。操做的複雜度爲O(N)。app
而SDS中len屬性中記錄了SDS的長度,因此獲取一個SDS的長度複雜度爲O(1)。函數
2.杜絕緩衝區溢出post
C字符串自己不記錄自身的長度,執行拼接字符串時,沒有預先擴容,則可能會出現內存其餘內容被意外修改
而SDSAPI須要對SDS進行修改時,API會先檢查SDS的空間是否知足修改所須要的要求,若是不知足的話,API會自動將SDS的空間擴展至執行修改所需的大小,而後才執行實際的修改操做
3.減小修改字符串時帶來的內存重分配次數
內存重分配
(1)空間預分配
優化SDS的字符串增加操做。
基於修改後的長度是否大於1MB,小於則將free屬性的值設置爲len的值;大於則將free屬性的值設爲1MB。
基於以上策略,當連續增加N次字符串所須要的內存重分配次數從一定N次下降爲最多N次。
(2)惰性空間釋放
優化SDS的字符串縮減操做。
當SDS的API須要縮短SDS保存的字符時,程序並不當即使用內存從新分配來回收縮短出來後多出來的字節,而是使用free屬性將這些字節的數量記錄起來,並等待未來使用。
以空間換時間
4.二進制安全
C字符串中的字符必須符合某種編碼,而且除了字符串的末尾以外,字符裏不能包含空字符,不然最早程序讀入的空字符串將被誤認爲是字符串結尾,致使C字符串只能保存文本數據。
因此SDS的API都是二進制安全的,全部SDS API都會以二進制的方式來處理SDS存放在buf數組裏的數據,程序不會對其中數據作任何限制、過濾、或者假設,數據在寫入時啥樣,讀取就是啥樣。
5.兼容部分C字符串函數
typedef struct listNode {
//前置節點
struct listNode *prev;
//後置節點
struct listNode *next;
}複製代碼