外部數據結構與內部數據結構
外部數據結構除了常用的5種:字符串String,哈希表Hash,列表List,集合Set,有序集合Sort Set,還有數據結構bitmap,HyperLogLog,Geo,Streams。外部結構對外使用,根據數據類型的不同,Redis內選用不同的內部結構。
這樣設計的好處是改變內部編碼對外部沒有影響(包裝者模式),外部的數據結構和命令無需改變,多種內部數據結構可以發揮各自的優勢。
外部數據、內部數據結構查看指令:
> set name zhangsan
OK
> type name
string
> object encoding name
embstr
1.string
- int 8個字節的長整型
- embstr 小于44個字節的字符串
- raw 大于44個字節小于512M的字符串
int
當value是整型時,內部就會使用int。
embstr與raw
embstr編碼將創建字符串對象所需的空間分配的次數從raw編碼的兩次降低為一次。因為embstr編碼的字符串對象的所有數據都保存在一塊連續的內存里面,所以這種編碼的字符串對象比起raw編碼的字符串對象能更好地利用緩存帶來的優勢。并且釋放embstr編碼的字符串對象只需要調用一次內存釋放函數,而釋放raw編碼對象的字符串對象需要調用兩次內存釋放函數。
2.hash
- 當filed的個數少于512,且沒有value大于64字節時,內部編碼為ziplist
- 當filed的個數大于512,或者value大于64字節時,內部編碼為hashtable
> hmset rank 1 yuwei 2 yuwei2 3 yuwei3
OK
> object encoding rank
ziplist
> hset rank 4 "Redis modules can access Redis built-in data structures both at high level, by calling Redis commands, and at low level, by manipulating the data structures directly."
1
> object encoding rank
hashtable
ziplist
list、hash、Sort Set三種外部結構,在某些情況下內部數據結構都使用了ziplist,因為ziplist充分體現了Redis對于存儲效率的追求。
一個普通的雙向鏈表,每一個節點都會占用一塊內容,各個節點通過指針連接,這種方式會產生大量的內存碎片,而且地址指針會占用額外的內存空間。ziplist將列表中的每一項存放在一塊連續的地址空間內,所以一個ziplist只占一塊大的內存。
hashtable
和Java中的HashMap一樣。
3.list
-
3.2之前
- 當列表list中的元素個數少于512,且沒有value大于64字節時,內部編碼為ziplist
- 當列表list中的元素個數大于512,或者value大于64字節時,內部編碼為linkedlist
-
3.2 之后
都使用quicklist
> rpush ques 123 234 2 > object encoding ques quicklist
linkedlist
雙向鏈表,沒啥說的。
quicklist
quicklist結合了雙向列表linkedlist和ziplist的特點,它是一個雙向無環鏈表,它的每一個節點都是一個ziplist,所有的節點都用quicklist存儲,省去了臨界時的格式轉換。
4.set
- 當集合set中的元素都是整數且元素個數小于512(默認時)使用intset
- 其它條件使用hashtable
> sadd ques 1 2 3
3
> object encoding ques
intset
> sadd ques aaa
1
> object encoding ques
hashtable
intset
Set特殊內部編碼,它是一個有序的整形數組,再內存分配上和ziplist有些類似,是連續的一塊內存空間。
5.Sort Set
- 元素個數少于128(默認為128),且沒有value大于64字節時,內部編碼為ziplist
- 元素個數大于128(默認為128),或者value大于64字節時,內部編碼為skiplist
> zadd ques 1 zhangsan 2 lisi
2
> object encoding ques
ziplist
> zadd ques 3 "Redis modules can access Redis built-in data structures both at high level, by calling Redis commands, and at low level, by manipulating the data structures directly."
1
> object encoding ques
skiplist
skiplist
Sorted set實現多維排序
Sorted set默認只使用一個因子進行排序,如果想要實現根據多個因子進行排序,比如外賣綜合排序需要考慮距離,評分,價格,就需要將多個排序因子轉換為一個排序因子,result = function(x, y, z)。
6.bitmap
bitmap實現了Redis的Bloom Filter(布隆過濾器)。
bitmap并不是一個真實的數據機構,它本質是String數據結構,不過操作的粒度是bit。String最大的長度是512M,所以bitmap允許存儲2^32個bit。
bloomFilter
Bloom Filter用于判斷一個元素是否存在于集合中,他的空間效率和時間效率遠超過一般的算法,不過會有一定的誤識別率(3%)。
當一個元素被加入集合時,通過K個散列函數將這個元素映射成一個位數組中的K個點,把它們置為1。檢索時,我們只要看看這些點是不是都是1就(大約)知道集合中有沒有它了:如果這些點有任何一個0,則被檢元素一定不在;如果都是1,則被檢元素很可能在。
Bloom Filter跟單哈希函數Bit-Map不同之處在于:Bloom Filter使用了k個哈希函數,每個字符串跟k個bit對應。從而降低了沖突的概率。
7.Geo
GEO功能在Redis3.2版本提供,使用Geo可以在Redis中存儲地理坐標,用來實現諸如附近位置、搖一搖這類依賴于地理位置信息的功能.
和bitmap一樣,Geo并不是一個數據結構,本質上是Sort Set,并且使用GeoHash技術進行填充。
8.HyperLogLog
HyperLogLog 是用來做基數統計的算法,基數統計的意思是一個集合中不重復元素的個數。即使元素的數量或體積特別大,計算基數所需要的空間是固定的,而且很小。
> PFADD hll a b c d e f g
1
> object encoding hll
raw
9.Streams
Streams是Redis5.0以后引入的數據結構,Streams就是Redis實現的內存版kafka。