Redis 是什麼?
Redis是一個開源(BSD許可)的,利用內存進行存儲的數據結構存儲系統;它可以用作數據庫、緩存和消息中間件。
- redis由意大利人 Salvatore Sanfilippo 使用C語言開發
- redis支持字符串(string)、列表(list)、集合(set)、有序集合(zset)、散列表(hash)五種基本數據結構類型
- redis從 2.2.0 版本開始支持bitmap;在 2.8.9 版本添加了 HyperLogLog 用以進行基數統計;在 3.2 版本中新增了對GEO(地理位置)的支持
- redis支持簡單事物與數據持久化,提供 RDB、AOF兩種可選的持久化方式
- redis可以用作數據庫、緩存、消息隊列等
Redis 數據結構
value 對應的五種數據結構
Redis存儲key-value鍵值對數據,其中key類型為字符串,value對應五種數據結構,如下圖所示:
- 字符串(string)類型的數據結構,對應的就是一個普通的字符串
- 散列表(hash)類型的數據結構,對應的就是一個hash table,散列表特別適合用於存儲對象
- 列表(list)類型的數據結構,對應的就是一個雙向列表,按照插入順序排序
- 集合(set)類型的數據結構,對應的就是一個string類型的無序集合,集合中的數據不能重複出現
- 有序集合(zset)類型的數據結構, 對應的就是一個string類型的有序集合,排序因子為每個元素附帶的一個double型的分數
Redis 核心對象 redisObject
在redis的 key-value存儲系統中,value 類型則為 redis 對象 redisObject, redisObject對象可以綁定對應的五種數據類型,如下圖所示:
- 數據類型(type),對應五種數據類型
- 編碼方式(encoding),指定所綁定數據類型的編碼方式
- 數據指針(ptr), 指向對象底層實現的數據結構
- 虛擬內存(vm), 該功能默認處於關閉狀態,只有打開了redis的虛擬內存功能,才會給vm分配真正的內存
編碼方式(encoding)
- raw RAW編碼方式使用簡單動態字符串來保存字符串對象,才有預分配空間的方式來避免字符串修改時頻繁的分配釋放內存
- int INT編碼方式以整數保存字符串數據,僅限能用long類型值表達的字符串
- embstr 從Redis 3.0版本開始字符串引入了EMBSTR編碼方式,長度小於OBJ_ENCODING_EMBSTR_SIZE_LIMIT(39)的字符串將以EMBSTR方式存儲。採用這個方式可以減少內存分配的次數,提高內存分配的效率,降低內存碎片率。
- hashtable 當數據類型無法滿足使用ziplist的條件時,Redis會使用hashtable作為數據結構的內部實現
- ziplist 列表(List),散列表(Hash),有序集合(Sorted Set)在成員較少,成員值較小的時候都會採用壓縮列表(ZIPLIST)編碼方式進行存儲;成員值”較小”的標準可以通過配置項進行配置;壓縮列表簡單來說就是一系列連續的內存數據塊,其內存利用率很高,但增刪改查效率較低,所以只會在成員較少,值較小的情況下使用。
- linkedlist 在Redis 3.2版本之前,一般的鏈表使用LINKDEDLIST編碼。在Redis 3.2版本開始,所有的鏈表都是用QUICKLIST編碼。兩者都是使用基本的雙端鏈表數據結構,區別是QUICKLIST每個節點的值都是使用ZIPLIST進行存儲的。
- skiplist 跳躍表(SKIPLIST)編碼方式為有序集合對象專用,有序集合對象採用了字典+跳躍表的方式實現;其中字典裡面保存了有序集合中member與score的鍵值對,跳躍表則用於實現按score排序的功能
- intset 當一個集合只包含整數值元素, 並且這個集合的元素數量不多時, Redis 就會使用整數集合作為集合鍵的底層實現
Redis這種通過redisObject指定數據結構編碼方式的設計有兩個好處:
- 可以改進內部編碼,而對外的數據結構和命令沒有影響,這樣一旦開發開發出優秀的內部編碼,無需改動外部數據結構和命令。
- 多種內部編碼實現可以在不同場景下發揮各自的優勢。例如ziplist比較節省內存,但是在列表元素比較多的情況下,性能會有所下降,這時候Redis會根據配置選項將列表類型的內部實現轉換為linkedlist。
Redis 五種數據結構對應的內部編碼
Redis在不同的情況下會為數據對象選擇適合的編碼方式
string
- int:8個字節的長整型
- embstr:小於等於39個字節的字符串
- raw:大於39個字節的字符串
hash
- ziplist(壓縮列表):當哈希類型元素個數小於hash-max-ziplist-entries配置(默認512個),同時所有值都小於hash-max-ziplist-value配置(默認64個字節)時,Redis會使用ziplist作為哈希的內部實現ziplist使用更加緊湊的結構實現多個元素的連續存儲,所以在節省內存方面比hashtable更加優秀
- hashtable(哈希表):當哈希類型無法滿足ziplist的條件時,Redis會使用hashtable作為哈希的內部實現。因為此時ziplist的讀寫效率會下降,而hashtable的讀寫時間複雜度為O(1)
list
- ziplist(壓縮列表):當哈希類型元素個數小於hash-max-ziplist-entries配置(默認512個)同時所有值都小於hash-max-ziplist-value配置(默認64個字節)時,Redis會使用ziplist作為哈希的內部實現
- linkedlist(鏈表):當列表類型無法滿足ziplist的條件時,Redis會使用linkedlist作為列表的內部實現
set
- intset(整數集合):當集合中的元素都是整數且元素個數小於set-max-intset-entries配置(默認512個)時,Redis會選用intset來作為集合內部實現,從而減少內存的使用。
- hashtable(哈希表):當集合類型無法滿足intset的條件時,Redis會使用hashtable作為集合的內部實現
zset
- ziplist(壓縮列表):當有序集合的元素個數小於zset-max-ziplist-entries配置(默認128個)同時每個元素的值小於zset-max-ziplist-value配置(默認64個字節)時,Redis會用ziplist來作為有序集合的內部實現,ziplist可以有效減少內存使用
- skiplist(跳躍表):當ziplist條件不滿足時,有序集合會使用skiplist作為內部實現,因為此時zip的讀寫效率會下降
reference
- redis中文官網
- 菜鳥教程-Redis
- Redis數據編碼方式詳解
- Redis的五種數據結構的內部編碼
閱讀更多 Haiyoung666 的文章