redis是一款開源的高性能key-value數據庫,廣泛應用于各種場景。在Redis中, 數據類型(Type)和編碼(Encoding) 是非常重要的概念。本篇博客將詳細介紹Redis支持的數據類型以及相應的編碼方式和底層實現原理。
要查看Redis某個key的內部編碼,可以使用Redis自帶的命令OBJECT ENCODING key。
其中,key是你想要查詢的鍵名。例如,如果你想要查詢名為mykey的鍵的內部編碼,可以執行以下命令:
127.0.0.1:6379> object encoding mykey // 查看某個Redis鍵值的編碼
一 、redisObject
在Redis中,redisObject 是一個非常重要的數據結構,它用于保存字符串、列表、集合、哈希表和有序集合等類型的值。以下是關于 redisObject 結構體的定義:
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:24; /* lru time (relative to server.lruclock) */
int refcount;
void *ptr;
} robj;
各個屬性解析如下:
- type:用于標識對象所屬的類型,分別是 REDIS_STRING、REDIS_LIST、REDIS_SET、REDIS_ZSET 和 REDIS_HASH 等。
- encoding: 用于標識對象內部的編碼方式, 如 REDIS_ENCODING_INT、REDIS_ENCODING_HT、REDIS_ENCODING_ZIPMAP 等。
- lru:這個字段記錄了對象被命令調用的時間, 它是緩存淘汰策略(LRU)的一部分。
- refcount:引用計數,當 refcount 減少到0時,對象就可以被清理并回收內存。
- ptr:一個指針,根據對象的類型和編碼方式的不同,這個指針可能會指向各種不同的類型,比如整數、動態字符串、鏈表、字典等。
其中,redisObject的encoding取值有如下幾種:
#define OBJ_ENCODING_RAW 0 //簡單動態字符串,用于保存鍵值對的鍵和配置文件中的參數。
#define OBJ_ENCODING_INT 1 //整型值,用于優化小整數的內存使用。
#define OBJ_ENCODING_HT 2 //哈希表,用于存儲普通哈希對象的字段和值。
#define OBJ_ENCODING_ZIPMAP 3 //縮字典,這是一種特殊類型的哈希表,用于優化小哈希對象的內存使用。
#define OBJ_ENCODING_LINKEDLIST 4 //雙端鏈表,用于存儲列表鍵。
#define OBJ_ENCODING_ZIPLIST 5 //壓縮列表,用于優化小列表或者小哈希對象的內存使用。
#define OBJ_ENCODING_INTSET 6 //整數集合,用于優化只包含整數元素的集合的內存使用。
#define OBJ_ENCODING_SKIPLIST 7 //跳躍表和字典,用于存儲有序集合鍵。
#define OBJ_ENCODING_EMBSTR 8 //對于長度小于44字節的字符串,Redis選擇使用此特殊的編碼方式。
#define OBJ_ENCODING_QUICKLIST 9 //對于列表對象(list object)的一種編碼方式。quicklist是ziplist和雙向鏈表的混合體。
三、Type與Encoding介紹
Redis支持五種主要的數據類型:字符串(String)、列表(List)、集合(Set)、有序集合(Sorted Set)和哈希(Hash)。
每種數據類型都有對應的編碼方式,數據類型與編碼方式總覽如下:
數據類型 |
編碼方式 |
字符串 |
int、embstr、raw |
哈希表 |
ziplist、hashtable |
列表 |
ziplist、linkedlist、quicklist |
集合 |
intset、hashtable |
有序集合 |
ziplist、skiplist |
1.字符串
字符串是Redis中最基本的數據類型,通常用于存儲文本或二進制數據。字符串在Redis中支持三種編碼方式:
- int:當字符串可以表示為整數時,Redis會將其轉換為整數,并采用int編碼方式存儲。int編碼方式的優點是存儲空間小,操作效率高。缺點是只能存儲整數,不支持字符串操作。
- embstr(embstr-encoded string) :保存長度小于44字節的字符串,當一個字符串比較短,采用此編碼方式存儲,可以減少內存占用。
- raw(raw-encoded string) :保存長度大于44字節的字符串,當一個字符串比較長時,采用此編碼方式存儲。
2.列表
列表是一系列有序的字符串集合,可以添加、修改和刪除元素。列表在Redis中支持三種編碼方式:
- ziplist:在Redis3.2版本之前,當List列表中每個字符串的長度都「小于64字節」并且List列表中「元素數量小于512個」時,List對象使用ziplist編碼,其他情況使用linkedlist編碼。ziplist是一種緊湊的、壓縮的列表結構,可以節省內存,適用于小型列表。
- linkedlist:linkedlist是一種鏈表結構,支持任意大小的列表。但其內存占用會隨著列表長度的增加而增加。
- quicklist:Redis 3.2版本引入,quicklist是一種由多個ziplist組成的列表結構,既能保證性能,又能節省內存,適用于大型列表。
3.集合
集合是一系列無序的字符串集合,支持添加、刪除和查詢元素。集合在Redis中支持兩種編碼方式:
- intset:當集合中的元素都是整數時,Redis會采用intset編碼方式存儲。intset編碼方式的優點是存儲空間小,操作效率高。
- hashtable:當集合中的元素包含字符串時,Redis會采用hashtable編碼方式存儲。hashtable編碼方式的優點是可以存儲任意類型的元素,支持字符串操作。缺點是存儲空間相對較大,操作效率相對較低。
4.有序集合
有序集合是一系列無序的字符串集合,每個元素關聯一個分數,可以根據分數排序。有序集合在Redis中支持兩種編碼方式:
- ziplist:當集合中元素個數少于128個,并且每個元素的大小小于64字節時,使用此編碼方式。這是因為ziplist在處理較小數據時,內存效率更高,性能更優。
- skiplist:skiplist是一種跳躍表結構,支持快速查詢和排序。適用于大型有序集合。
5.哈希表
哈希表是一系列鍵值對集合,每個鍵關聯一個值。哈希表在Redis中支持兩種編碼方式:
- ziplist:保存的所有鍵值的字符串長度小于64字節,并且鍵值對數量小于512個,Redis會采用ziplist編碼方式存儲。ziplist編碼方式的優點是存儲空間小,操作效率高。缺點是不支持快速的鍵查找操作。
- hashtable:除上述條件之外,Redis會采用hashtable編碼方式存儲。hashtable編碼方式的優點是支持快速的鍵查找操作,缺點是存儲空間相對較大,操作效率相對較低。
四、Type與Encoding底層原理
了解Redis支持的數據類型和編碼方式后,我們來看一下它們的底層實現原理。
1.編碼轉換
Redis中的每個鍵值對都有一個類型標識,表示該鍵值對的數據類型。當我們對一個鍵進行操作時,Redis會根據該鍵當前的編碼方式以及操作所需的編碼方式,對鍵值對進行編碼轉換。
例如,當我們向一個字符串中追加內容時,如果該字符串當前的編碼方式為raw,但是新的內容可以使用embstr編碼方式存儲,那么Redis會將該字符串的編碼方式從raw轉換為embstr。
2.數據結構
除了編碼方式外,Redis還使用了許多經典的數據結構來實現各種數據類型。例如,Redis的列表和哈希表都是采用鏈表結構實現的。而有序集合則采用了跳躍表(Skip List)這種高效的數據結構。
這些數據結構都經過了精心設計和優化,以滿足各種場景下的應用需求。例如,鏈表結構適合頻繁地添加和刪除元素,而跳躍表結構則適合排序和查找。
本篇博客介紹了Redis支持的五種主要數據類型以及相應的編碼方式。
Redis的數據類型和編碼方式是為了在不同的場景下達到最佳的性能和內存占用。理解這些類型和編碼機制,對于深化我們對Redis的認識,優化其性能,以及發揮其最大潛力是至關重要的。
雖然每個項目的需求和應用可能會有所不同,但通過精心選擇和使用合適的類型和編碼,我們都可以充分利用Redis為我們的應用帶來的高效,快速和可靠。
總之,Redis的類型和編碼是其核心功能的基石,理解這些可以幫助我們更好地使用Redis,解決實際問題。當你下次面臨需要決定使用哪種數據結構或編碼方式的時候,希望你可以記住今天的內容,并從中找到答案。感謝您抽出寶貴的時間閱讀這篇文章,希望它對您有所幫助!