redis 對象

redis經過前面幾篇的數據結構構鍵了一個對象系統,這個對象系統包含了字符串對象,列表對象,哈希對象,集合對象,有序集合對象redis

每個對象都是一個redisobjectwindows

typedef struct redisObject {

    // 類型
    unsigned type:4;

    // 編碼
    unsigned encoding:4;

    // 指向底層實現數據結構的指針
    void *ptr;

    // ...

} robj;

type表示類型,有5種,就是緩存

REDIS_STRING,REDIS_LIST,REDIS_HASH,REDIS_SET,REDIS_ZSET服務器

編碼表示的就是底層的實現,由於每一種對象都至少有兩種以上的實現方式。ptr指向的就是底層實現的數據結構數據結構

 

字符串對象的編碼能夠是int,raw,embstrapp

int針對的是整數函數

若是字符串的長度小於39,那麼使用embram,不然使用raw優化

embstr和raw的區別編碼

(1)embstr是連續的,object和sds是一塊連續的內存,這樣的話分配內存和釋放內存都不是兩次,而是一次spa

(2)充分利用緩存的優點

double類型其實也是字符串類型的

當時用的時候會從字符串類型轉換爲double類型

int和embstr在知足條件的時候都會轉換爲raw編碼,好比一個整數10085 appending一個字符串的話就不在是一個整數了

另外embsr不能夠修改的,他是隻讀的,若是要修改的話,他會自動轉換爲raw以後再進行修改

 

 

 

列表對象:

列表對象的編碼可使壓縮列表和雙端鏈表,若是其中有字符串的話,字符串是字符串對象的表示,說明字符串對象能夠被其餘的對象嵌套

編碼轉換

(1)每個元素得長度都小於64,

(2)數量小於512,

知足上面兩個條件的話就是用壓縮列表,不然的話使用雙端鏈表

 

 

哈希對象

哈希對象的編碼能夠是壓縮列表和字典

以下圖所示

至於編碼的轉換,和上面的是同樣的,若是兩個都知足,就使用壓縮列表,不然使用字典

ps:注意這兩個限制條件在redis.conf的配置文件中是能夠修改的

 

 

集合對象:

集合對象的編碼能夠是整數集合和hashtable

看下面:

 

 

 編碼的轉換條件

(1)都是整數

(2)元素數量不超過512個

知足以上條件使用整數集合,不然的話使用hashtable

 

 

有序集合對象:

編碼能夠是壓縮列表和跳躍表

壓縮列表實現的話,使按照分值排序,而且存儲的話對象在前,分值在後

 

 

zset中基於跳躍表實現的話,就是講分值從小到大排序,創建一個跳躍表,可是額外還須要一個字典,記錄對象和分值的映射,這樣的話對於ZSCORE命令,咱們能夠在O(1)的時間複雜度就能夠得到到指定對象的分值

 

二者結合,不管是有序遍歷仍是得到指定元素,都會擇優選擇,下降時間複雜度

編碼轉換

(1)長度都小於64

(2)數量不超過128個

這兩個都知足就是用壓縮列表,否者就是用skiplist做爲編碼

 

 

 

額外對於對象還有不少優化和處理

(1)多態:不少命令都是具備多態的性質,就是能夠處理多種命令

 

在執行一個命令的時候,咱們首先會根據值對象的類型去判斷這個命令可否執行,若是能夠的話,咱們還會根據值對象的編碼方式選擇正確的API去執行

好比上面,咱們就能夠認爲LLEN是多態的,多態能夠包括基於類型的多態,和基於編碼的多態

 

(2)內存管理:

對於redisobject咱們基於引用計數原值,定義在redisobject結構裏面的refcount int,當對象引用計數下降爲0的時候,釋放對象。這個有點相似windows線程回收機制,採用計數原值,關閉handle減一,線程函數退出減一,爲0的時候自動回收線程資源

 

(3)對象共享:

redis中多個鍵的值同樣的話,會使值指針只想一塊內存,引用計數增長,redis服務器初始化的時候會默認建立0-9999字符串,因此他們的引用計數在還沒使用的時候就是1了

 

(4)空轉時長:

redisobject中有個lru,表示最後訪問的時候

經過idletime能夠求出多久沒有被訪問了,就是當前時間和lru時間差(空轉時長)

可是ps(這個命令不會修改lru屬性)

若是服務器設置了maxmemory選項,那麼當內存達到上線了,服務器會優先空轉時間長的進行釋放

相關文章
相關標籤/搜索