學習《redis入門指南》筆記,結合實踐,只記錄重要,明確,屬於新知的相關內容。redis
一、redis對於它所支持的五種數據類型,每種都提供了兩種及以上的編碼方式去存儲(具體對應的編碼方式能夠百度)。由於基於內存的緣故,因此爲了平衡時間與空間的使用效率在元素數量較多或較少時採用不一樣的策略,固然對於使用者這是透明的。數據結構
二、查看redis鍵值的內部編碼方式性能
OBJECT ENCODING key學習
三、對於每個鍵,都會有一個結構去存儲它的數據類型,編碼格式,數據地址等信息。優化
1 typedef struct redisObject 2 { 3 unsigned type:4; // 這種語法叫作位字段 4 unsigned notused:2; 5 unsigned encoding:4; 6 unsigned lru:22; 7 int refcount; 8 void *ptr; 9 }
四、對於字符串類型(示意結構以下),鍵值能夠用一個64位整數表示時,就會使用數據指針表示數據內容(REDIS_ENCODING_INT編碼方式),以節省空間;redis3.0引入了REDIS_ENCODING_EMBSTR編碼方式,在鍵值長度小於39時,字符串自己就會跟在redisObject結構以後,減小申請釋放內存次數;當對REDIS_ENCODING_EMBSTR編碼方式的字符串作任何修改後,都會改成REDIS_ENCODING_RAW編碼方式;redis啓動後,會預先創建10000個從0~9999這些數字的redisObject結構,當咱們set這些值時會直接引用向它們,並自增refcount這個引用,但若是在配置文件參數中設置了maxmemory參數,將不會預先存儲這些共享對象。ui
1 struct shshdr // 僅僅是示意結構 2 { 3 int len; 4 int free; 5 char buf[]; 6 }
五、對於散列類型,當字段個數小於hash-max-ziplist-entries(配置文件參數,默認512)而且每一個字段值長度小於hash-max-ziplist-value(配置文件參數,默認64)時,採用REDIS_ENCODING_ZIPLIST(示意結構以下)編碼,不然採用REDIS_ENCODING_HT(真正的散列表);對於redis的鍵值對存儲也是用散列表,但並不使用redisObject結構,因此數字鍵名不會比字符串名節省空間。編碼
1 zlbytes // uint32 整個結構佔用的空間 2 zltail // uint32 末尾元素偏移 3 zllen // unit16 元素數量 ———————————————————— 4 元素1 ----------------------> | 前一個元素大小 | 5 元素2 | 當前元素的編碼類型 | 6 元素3 | 當前元素大小 | 7 ...... | 當前元素內容 | 8 zlend // 結尾標識,永遠爲255 ————————————————————
REDIS_ENCODING_ZIPLIST中的每一個元素由四部分構成。spa
第一部分存儲前一個元素大小,用於倒序查找,當前一個元素小於254字節時,第一部分佔用一個字節,不然佔用5個字節;指針
第2、三部分爲元素編碼類型和大小,當元素長度不大於63字節時,編碼爲ZIP_STR_06B(即0<<6),同時第三部分用6個二進制位記錄長度,此時2、三部分佔用一個字節;當元素長度大於63且小於16383字節時,2、三部分佔用2字節,大於16383時佔用5字節;code
第四部分若是元素內容能夠轉爲數字的話會用相應數字存儲,並用2、三部分來表示元素數字的類型(int16_t,int32_t等)。
使用REDIS_ENCODING_ZIPLIST存儲散列類型時,元素1存儲字段1,元素2存儲字段1值;插入,刪除,查找(一跳一跳查找,跳過字段值)時都將移動後面的元素或遍歷,所以上文的兩個參數不能過大。
六、對於列表類型,有REDIS_ENCODING_LINKEDLIST 和REDIS_ENCODING_ZIPLIST兩種編碼,也有list-max-ziplist-entries和list-max-ziplist-value兩個參數控制變換編碼的時機;REDIS_ENCODING_LINKEDLIST即雙向鏈表,優化方式與字符串類型的鍵值相同;較新版本的redis增長了REDIS_ENCODING_QUICKLIST編碼方式,它將一個長列表分紅若干個以鏈表形式組織的ziplist,在減小空間佔用的同時,提示REDIS_ENCODING_ZIPLIST編碼的性能。
七、對於集合類型,有REDIS_ENCODING_HT和REDIS_ENCODING_INTSET(結構以下),當元素都爲整數且元素個數小於set-max-intset-entries(配置文件參數,默認512)時,採用REDIS_ENCODING_INTSET;intset默認的encoding是INTSET_ENC_INT16(即2字節),當沒法知足時會升級爲INTSET_ENC_INT32或INTSET_ENC_INT64,同時調整以前的元素;intset按序存儲,採用二分查找,插入和刪除效率較低;當初先非數字元素時,編碼馬上變爲REDIS_ENCODING_HT,此時即使將非數字元素刪除,編碼也不會迴轉。
1 typedef struct intset 2 { 3 uint32_t encoding; 4 uint32_t length; 5 int8_t contents[]; 6 } intset;
八、對於有序集合類型,有REDIS_ENCODING_SKIPLIST和REDIS_ENCODING_ZIPLIST,一樣有兩個參數zset-max-ziplist-entries和zset-max-ziplist-value去控制什麼時候變換編碼爲跳躍表REDIS_ENCODING_SKIPLIST;在這種編碼方式下使用兩種數據結構來存儲有序集合類型鍵值,散列表用來存儲元素值與元素分數的映射關係以實現O(1)時間複雜度的命令,跳躍表存儲元素分數及到元素的映射用以實現排序功能;這裏的跳躍表容許分數相同的元素存在,而且增長了指向前一個元素的指針以實現倒序查找;此時元素值是用redisObject結構存儲的,與字符串類型鍵值優化方式相同,分數按照double存儲;採用REDIS_ENCODING_ZIPLIST時,按照「元素1的值,元素1的分數」的順序排列,而且分數是有序的。