面試:原來Redis經常使用的五種數據類型底層結構是這樣的

關注我,能夠獲取最新知識、經典面試題以及微服務技術分享面試

  在Redis中會涉及不少數據結構,好比SDS,雙向鏈表、字典、壓縮列表、整數集合等等。Redis會基於這些數據結構自定義一個對象系統,並且自定義的對象系統有不少好處。redis

經過對如下的Redis對象系統的學習,能夠了解Redis設計原理以及初衷,爲了咱們在使用Redis的時候,更加可以理解到其原理和定位問題。數據庫

Redis 對象

Redis基於上述的數據結構自定義一個Object 系統,Object結構:數據結構

redisObject結構:
     typedef struct redisObject{
    //類型
    unsigned type:4;
    //編碼
    unsigned encoding:4;
    //指向底層實現數據結構的指針
    void *ptr;
    ….. 
}

Object 系統包含五種Object:app

  • String:字符串對象
  • List:列表對象
  • Hash:哈希對象
  • Set:集合對象
  • ZSet:有序集合

Redis使用對象來表示數據庫中的鍵和值,即每新建一個鍵值對,至少建立有兩個對象,並且使用對象的具備如下好處:微服務

1. redis能夠在執行命令前會根據對象的類型判斷一個對象是否能夠執行給定的命令
2. 針對不一樣的使用場景,爲對象設置不一樣的數據結構實現,從而優化對象的不一樣場景夏的使用效率
3. 對象系統還能夠基於引用計數計數的內存回收機制,自動釋放對象所佔用的內存,或者還可讓多個數據庫鍵共享同一個對象來節約內存。
4. redis對象帶有訪問時間記錄信息,使用該信息能夠進行優化空轉時長較大的key,進行刪除!



對象的ptr指針指向對象的底層現實數據結構,而這些數據結構由對象的encoding屬性決定,對應關係:學習

編碼常量 編碼對應的底層數據結構
REDIS_ENCODING_INT long類型的整數
REDIS_ENCODING_EMBSTR embstr編碼的簡單動態字符串
REDIS_ENCODING_RAW 簡單動態字符串
REDIS_ENCODING_HT 字典
REDIS_ENCODING_LINKEDLIST 雙向鏈表
REDIS_ENCODING_ZIPLIST 壓縮列表
REDIS_ENCODING_INTSET 整數集合
REDIS_ENCODING_SKIPLIST 跳躍表和字典



每種Object對象至少有兩種不一樣的編碼,對應關係:優化

類型 編碼 對象
String int 整數值實現
String embstr sds實現 <=39 字節
String raw sds實現 > 39字節
List ziplist 壓縮列表實現
List linkedlist 雙端鏈表實現
Set intset 整數集合使用
Set hashtable 字典實現
Hash ziplist 壓縮列表實現
Hash hashtable 字典使用
Sorted set ziplist 壓縮列表實現
Sorted set skiplist 跳躍表和字典


String 對象

字符串對象編碼能夠int 、raw或者embstr,若是保存的值爲整數值且這個值能夠用long類型表示,使用int編碼,其餘編碼相似。ui

好比:int編碼的String Object編碼

redis> set number 520 
 ok
 redis> OBJECT ENCODING number 
"int"

String Object結構:

file

### String 對象之間的編碼轉換
int編碼的字符串對象和embstr編碼的字符串對象在條件知足的狀況下,會被轉換爲raw編碼的字符串對象。

好比:對int編碼的字符串對象進行append命令時,就會使得原來是int變爲raw編碼字符串


List對象

list對象能夠爲ziplist或者爲linkedlist,對應底層實現ziplist爲壓縮列表,linkedlist爲雙向列表。

Redis>RPUSH numbers 「Ccww」 520 1

用ziplist編碼的List對象結構:
file

用linkedlist編碼的List對象結構:

file

List對象的編碼轉換:

當list對象能夠同時知足如下兩個條件時,list對象使用的是ziplist編碼:

1. list對象保存的全部字符串元素的長度都小於64字節
2. list對象保存的元素數量小於512個,

不能知足這兩個條件的list對象須要使用linkedlist編碼。

Hash對象

Hash對象的編碼能夠是ziplist或者hashtable
其中,ziplist底層使用壓縮列表實現:

  • 保存同一鍵值對的兩個節點緊靠相鄰,鍵key在前,值vaule在後
  • 先保存的鍵值對在壓縮列表的表頭方向,後來在表尾方向

hashtable底層使用字典實現,Hash對象種的每一個鍵值對都使用一個字典鍵值對保存:

  • 字典的鍵爲字符串對象,保存鍵key
  • 字典的值也爲字符串對象,保存鍵值對的值

好比:HSET命令

redis>HSET author name  "Ccww"
(integer)

redis>HSET author age  18
(integer)

redis>HSET author sex  "male"
(integer)

ziplist的底層結構:

file

hashtable底層結構:

file

Hash對象的編碼轉換:

當list對象能夠同時知足如下兩個條件時,list對象使用的是ziplist編碼:

1. list對象保存的全部字符串元素的長度都小於64字節
2. list對象保存的元素數量小於512個,

不能知足這兩個條件的hash對象須要使用hashtable編碼

Note:這兩個條件的上限值是能夠修改的,可查看配置文件hash-max-zaiplist-value和hash-max-ziplist-entries


Set對象:

Set對象的編碼能夠爲intset或者hashtable

  • intset編碼:使用整數集合做爲底層實現,set對象包含的全部元素都被保存在intset整數集合裏面
  • hashtable編碼:使用字典做爲底層實現,字典鍵key包含一個set元素,而字典的值則都爲null

inset編碼Set對象結構:

redis> SAD number  1 3 5

file

hashtable編碼Set對象結構:

redis> SAD Dfruits  「apple」  "banana" " cherry"

file

Set對象的編碼轉換:

使用intset編碼:

1. set對象保存的全部元素都是整數值
2. set對象保存的元素數量不超過512個

不能知足這兩個條件的Set對象使用hashtable編碼

ZSet對象

ZSet對象的編碼 能夠爲ziplist或者skiplist
ziplist編碼,每一個集合元素使用相鄰的兩個壓縮列表節點保存,一個保存元素成員,一個保存元素的分值,而後根據分數進行從小到大排序。

ziplist編碼的ZSet對象結構:

Redis>ZADD price 8.5 apple 5.0 banana 6.0 cherry

file

skiplist編碼的ZSet對象使用了zset結構,包含一個字典和一個跳躍表

Type struct zset{

    Zskiplist *zsl;
    dict *dict;
    ...
}

skiplist編碼的ZSet對象結構

file

ZSet對象的編碼轉換

當ZSet對象同時知足如下兩個條件時,對象使用ziplist編碼

1. 有序集合保存的元素數量小於128個
2. 有序集合保存的全部元素的長度都小於64字節

不能知足以上兩個條件的有序集合對象將使用skiplist編碼。

Note:能夠經過配置文件中zset-max-ziplist-entries和zset-max-ziplist-vaule

相關文章
相關標籤/搜索