面試官:Redis中集合資料型別的內部實現方式是什麼?

萬貓學社發表於2022-03-12

雖然已經是陽春三月,但騎著共享單車騎了這麼遠,還有有點冷的。我搓了搓的被凍的麻木的手,對著前臺的小姐姐說:“您好,我是來面試的。”小姐姐問:“您好,您叫什麼名字?”我回答:“我叫萬貓學社。”小姐姐笑出了聲,說到:“這名字好怪,誰給你起的啊。”我面無表情地回答:“俺爹。”小姐姐收起了笑容,說到:“跟我來吧。”我被帶到了面試間等候,片刻後一個著乾淨滿臉清秀的青年走了進來,一股男士香水的淡香撲面而來。

面試官:Redis中基本的資料型別有哪些?

我:Redis的基本資料型別有:字串(string)、雜湊(hash)、列表(list)、集合(set)、有序集合(zset)。

面試官:集合資料型別的內部實現方式是什麼?

我還沉浸在上一個問題的沾沾自喜中,頓時表情凝固了,手心開始冒出冷汗。“這個。。沒有太深入瞭解”,我支支吾吾的說到。

面試官:回去等訊息吧。

這句話說的乾淨利落,然後就沒有然後了。失敗是成功的媽媽,我不氣餒,決定馬上惡補一下。

型別和編碼

首先,整明白什麼是型別?什麼是編碼?在Redis中使用物件來表示記憶體中的鍵和值。每個物件由一個叫做redisObject結構體表示,其中有三個屬性:型別(type)、編碼(encoding)、指向具體資料的指標(ptr)。

我們通常說的字串、雜湊、列表、集合、有序集合都是redisObject中的型別,實際上針對每一個資料結構在Redis內部都有自己底層的多種內部編碼實現,這樣是為了在合適的場景選擇合適的內部編碼,以達到記憶體空間和處理效率的平衡,這可能就是中庸之道吧。

在面試中,經常被問到的內部實現方式、內部構造、內部原理,一般指的就是redisObject中的編碼

集合的編碼

集合的編碼有兩種,分別是:整數集合(intset)和雜湊表(hashtable)。

當集合中的所有元素都是整數,並且元素的個數小於set-max-intset-entries(預設為512個)時,使用整數集合作為集合的編碼,集合的所有元素都儲存在整數集合裡面。比如:

127.0.0.1:6379> sadd one-more-set 1 2 3 4 5
(integer) 5
127.0.0.1:6379> smembers one-more-set
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> object encoding one-more-set
"intset"

當集合中的所有元素不都是整數,或者元素的個數大於等於set-max-intset-entries(預設為512個)時,使用雜湊表作為集合的編碼,雜湊表的每一個鍵都是字串物件,每一個字串包含一個集合的元素,雜湊表的值全部為NULL

比如,集合中的所有元素不是整數:

127.0.0.1:6379> sadd one-more-set one more
(integer) 2
127.0.0.1:6379> smembers one-more-set
1) "more"
2) "one"
127.0.0.1:6379> object encoding one-more-set
"hashtable"

當然,瞭解以上細節還沒能完全“征服”面試官,我們需要更深入一些:)

集合的編碼轉換

當一個集合是以整數集合為編碼時,再向這個集合新增非整數的元素,或向這個集合新增整數的元素使元素個數過多時,就會執行集合的編碼轉換。

把原來儲存在整數集合中的所有元素轉移到雜湊表中,並且把集合的編碼用整數集合修改為雜湊表。不過,把非整數的元素從集合中移除,或者減少整數元素的個數,以雜湊表為編碼的集合也不會轉化為整數集合。

舉個例子,我們先建立一個以整數集合為編碼的集合:

127.0.0.1:6379> sadd one-more-set 1 2 3 4 5
(integer) 5
127.0.0.1:6379> smembers one-more-set
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> object encoding one-more-set
"intset"

然後,再向它新增兩個字串元素,它就是轉換為以雜湊表為編碼:

127.0.0.1:6379> sadd one-more-set one more
(integer) 2
127.0.0.16379> smembers one-more-set
1) "one"
2) "5"
3) "1"
4) "2"
5) "more"
6) "4"
7) "3"
127.0.0.1:6379> object encoding one-more-set
"hashtable"

然後,再把那兩個字串元素從集合中移除,集合的編碼依然是雜湊表:

127.0.0.1:6379> srem one-more-set one more
(integer) 2
127.0.0.1:6379> smembers one-more-set
1) "5"
2) "1"
3) "2"
4) "4"
5) "3"
127.0.0.1:6379> object encoding one-more-set
"hashtable"

總結

在Redis中,集合的內部實現有整數集合(intset)和雜湊表(hashtable)兩種,當集合中的所有元素都是整數並元素個數較少時,使用整數集合作為內部實現,否則使用雜湊表作為內部實現。當條件不滿足時,整數集合可以轉換為雜湊表,但雜湊表不能轉換為整數集合。

最後,謝謝你這麼帥,還給我點贊關注

微信公眾號:萬貓學社

微信掃描二維碼

關注後回覆「電子書」

獲取12本Java必讀技術書籍

面試官:Redis中集合資料型別的內部實現方式是什麼?

相關文章