1. 程式人生 > >Redis之物件

Redis之物件

redis並沒有直接使用我們之前介紹的那些資料結構來實現鍵值對資料庫,而是基於這些資料結構建立了一個物件系統,這個系統包含字串物件、列表物件、雜湊物件、集合物件、有序集合物件五種型別的物件,每種物件都用到了至少一種我們前面所介紹的資料結構。通過這五種不同型別的物件,redis可以在執行命令之前,根據物件的型別來判斷一個物件是否可以執行給定的命令。除此之外,redis的物件系統還實現了基於引用計數計數的記憶體回收機制,當程式不再使用某個物件的時候,這個物件所佔用的記憶體就會被自動釋放;另外,redis還通過引用計數計數實現了物件共享機制,這一機制可以在適當的條件下,通過多個數據庫鍵共享同一個物件來節約記憶體。最後redis的物件帶有訪問時間記錄資訊,該資訊可以用於計算資料庫鍵的空轉時長。 物件型別及編碼

typedef struct redisObject {

    // 型別
    unsigned type:4;

    // 編碼
    unsigned encoding:4;

    // 物件最後一次被訪問的時間
    unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */

    // 引用計數
    int refcount;

    // 指向實際值的指標
    void *ptr;

} robj

每次當我們在redis的資料庫中新建立一個鍵值對時,我們至少會建立兩個物件,一個物件用作鍵值對的鍵,另一個物件用作鍵值對的值。 type:型別

ptr:指向物件的底層實現資料結構,而這些資料結構僅有物件的encoding屬性決定 encoding:記錄了物件所使用的編碼 在這裡插入圖片描述 每種型別的物件都至少使用了兩種不同的編碼 在這裡插入圖片描述 字串物件 字串物件的編碼可以是int、raw、embstr 如果一個字串物件儲存的時整數值,並且這個數值可以用long型別來表示,那麼字串物件會將整數值儲存在字串物件結構的ptr屬性裡面,並將字串物件的編碼設定為int。 如果字串物件儲存的是一個字串值,並且這個字串值的長度大於32位元組,那麼字串物件將使用一個簡單動態字串來儲存這個字串值,並將物件的編碼設定為raw。 如果字串物件儲存的是一個字串值,並且這個字串值的長度小於等於32位元組,那麼字串物件將使用embstr編碼的方式來儲存這個二字串值。 embstr編碼是專門用於儲存短字串的一種優化編碼方式,raw編碼會呼叫兩次記憶體分配函式來分別建立redisObject結構和sdshdr結構,而embstr編碼則通過呼叫一次記憶體分配函式來分配一塊連續的空間,空間一次包含redisObject和sdshdr。 列表物件 列表物件的編碼可以是ziplist或者linkedlist ziplist編碼的列表物件使用壓縮列表作為底層實現,每個壓縮列表節點儲存了一個列表元素 在這裡插入圖片描述

linkedlist編碼的列表物件使用雙端連結串列作為底層實現,每個雙端連結串列節點都儲存了一個字串物件,而每個字串物件都儲存了一個列表元素 在這裡插入圖片描述

當列表物件可以同時滿足以下兩個條件時,列表物件使用ziplist編碼: 1、列表物件儲存的所有字串元素的長度都小於64位元組 2、列表物件儲存的元素數量小於512個;不能滿足這兩個條件的列表物件需要使用linkedlist編碼 雜湊物件 雜湊物件的編碼可以是ziplist或者hashtable ziplist編碼的雜湊物件使用壓縮列表作為底層實現,每當有新的鍵值對要加入到雜湊物件時,程式會先將儲存了鍵的壓縮列表節點推入到壓縮列表表尾,然後再將儲存了值的壓縮列表節點推入到壓縮列表的表尾 在這裡插入圖片描述 在這裡插入圖片描述 hashtable編碼的雜湊物件使用字典作為底層實現: 在這裡插入圖片描述

當雜湊物件可以同時滿足以下兩個條件時,雜湊物件使用ziplist編碼: 1、雜湊物件儲存的所有鍵值對的鍵和值的字串長度都小於64位元組 2、雜湊物件儲存的鍵值對數量小於512個 集合物件 集合物件的編碼可以是inset或者hashtable 在這裡插入圖片描述 當集合物件可以同時滿足以下兩個條件時,物件使用inset編碼: 1、集合物件儲存的所有元素都是整數值 2、集合物件儲存的元素數量不超過512個 有序集合物件 有序集合物件的編碼可以是ziplist或者skiplist skiplist編碼的有序集合物件使用zset結構作為底層實現,一個紫色調結構同時包含一個字典和一個跳躍表 在這裡插入圖片描述 當有序集合物件可以同時滿足以下兩個條件時,物件使用ziplist編碼: 1、有序集合儲存的元素數量小於128個 2、有序集合儲存的所有元素成員的長度都小於64位元組 型別檢查與命令多型 redis中用於操作鍵的命令基本可以分為兩種型別 1、可以對任何型別鍵執行 2、只能對特定型別的鍵執行 型別檢查的實現 型別特定命令鎖進行的型別檢查是通過redisObject結構的type屬性來實現的: 1、在執行一個型別特定命令前,伺服器會先檢查輸入資料庫鍵的值物件是否為執行命令所需型別,如果是的話, 伺服器就對鍵執行指定的命令 2、否則,伺服器將拒絕執行命令,並向客戶端返回一個型別錯誤 在這裡插入圖片描述 多型命令的實現 redis除了會根據值物件的型別來判斷鍵是否能夠執行指定命令之外,還會根據值物件的編碼方式,選擇正確的命令實現程式碼來執行命令 在這裡插入圖片描述 記憶體回收 redis在自己的物件系統中構建了一個引用計數技術實現的記憶體回收機制,通過這一機制,程式可以通過跟蹤物件的引用計數資訊,在適當的時候自動釋放物件並進行記憶體回收。 物件的引用計數資訊會隨著物件的使用狀態而不斷變化: 1、在建立一個新物件時,引用計數的值湖北初始化為1 2、當一個新程式使用時,它的引用計數值會被贈一 3、當物件不再被一個程式使用時,它的引用計數值會被減一 4、當物件的引用計數值變為0時,物件所佔用的記憶體會被釋放 物件共享 除了用於實現引用計數記憶體回收機制之外,物件的引用計數屬性還帶有物件的共享作用。目前來說,redis會在初始化伺服器時,建立一萬個字串物件,這些物件包含了從0到9999的所有整數值,當伺服器需要用到值為0到9999的字串物件時,伺服器就會使用這些共享物件。 物件的空轉時長:lru記錄了物件最後一次被命令程式訪問的時間。