Redis常用数据类型的数据结构
文章目錄
- 1. Redis 數(shù)據(jù)庫介紹
- 2. 列表(list)
- 3. 字典(hash)
- 4. 集合(set)
- 5. 有序集合(sortedset)
- 6. 數(shù)據(jù)結(jié)構(gòu)持久化
- 7. 總結(jié)
 
1. Redis 數(shù)據(jù)庫介紹
Redis 是一種鍵值( Key-Value )數(shù)據(jù)庫。相對于關(guān)系型數(shù)據(jù)庫(比如MySQL),Redis也被叫作 非關(guān)系型 數(shù)據(jù)庫。
- 像MySQL 這樣的關(guān)系型數(shù)據(jù)庫,表的結(jié)構(gòu)比較復(fù)雜,會包含很多字段,可以通過SQL語句,來實現(xiàn)非常復(fù)雜的查詢需求。
- 而Redis中只包含“鍵”和“值”兩部分,只能通過“鍵”來查詢“值"。正是因為這樣簡單的存儲結(jié)構(gòu),讓Redis的讀寫效率非常高。
- Redis 主要是作為內(nèi)存數(shù)據(jù)庫來使用,數(shù)據(jù)是存儲在內(nèi)存中的。它也支持將數(shù)據(jù)存儲在硬盤中。
Redis中,鍵的數(shù)據(jù)類型是字符串,值的數(shù)據(jù)類型有很多,常用的分別是字符串、列表、字典、集合、有序集合。
“字符串(string)"這種數(shù)據(jù)類型非常簡單,對應(yīng)到數(shù)據(jù)結(jié)構(gòu)里,就是字符串。
2. 列表(list)
列表這種數(shù)據(jù)類型支持存儲一組數(shù)據(jù)。其對應(yīng)兩種實現(xiàn),一種是壓縮列表(ziplist),另一種是雙向循環(huán)鏈表。
- 列表中數(shù)據(jù)量比較小的時候,就可以采用壓縮列表的方式實現(xiàn)。具體需要同時滿足下面兩個條件:
壓縮列表,并不是基礎(chǔ)數(shù)據(jù)結(jié)構(gòu),是Redis自己設(shè)計的一種數(shù)據(jù)存儲結(jié)構(gòu)。它有點類似數(shù)組,通過一片連續(xù)的內(nèi)存,來存儲數(shù)據(jù)。它跟數(shù)組不同的一點是,它允許存儲的 數(shù)據(jù)大小不同 。存儲結(jié)構(gòu)如圖。
 
 壓縮列表中的“壓縮”如何理解?
-  節(jié)省內(nèi)存,是相較于數(shù)組而言的。數(shù)組要求每個元素的大小相同,如果我們要存儲不同長度的字符串,就需要用最大長度的字符串大小作為元素的大小(假設(shè)是20個字節(jié))。當我們存儲小于20個字節(jié)長度的字符串的時候,便會浪費部分存儲空間。如圖。 
 
-  支持不同類型數(shù)據(jù)的存儲。因為數(shù)據(jù)存儲在一片連續(xù)的內(nèi)存空間,通過鍵來獲取值為列表類型的數(shù)據(jù),讀取的效率也非常高。 
-  列表中數(shù)據(jù)量比較大的時候,也就不能同時滿足剛剛講的兩個條件,列表就要通過雙向循環(huán)鏈表來實現(xiàn)。 
Redis的雙向鏈表實現(xiàn)方式,非常值得借鑒。它額外定義一個list結(jié)構(gòu)體,來組織鏈表的首、尾指針,還有長度等信息。在使用的時候非常方便。
// 以下是 C 語言代碼,因為 Redis 是用 C 語言實現(xiàn)的。 typedef struct listnode {struct listNode *prev;struct listNode *next;void *value; } listNode;typedef struct list {listNode *head;listNode *tail;unsigned long len;// .... 省略其他定義 } list;3. 字典(hash)
字典類型用來存儲一組數(shù)據(jù)對。每個數(shù)據(jù)對又包含鍵值兩部分。字典類型也有兩種實現(xiàn)方式。
- 一種是壓縮列表,另一種是散列表。
同樣,當存儲數(shù)據(jù)量比較小的情況下,Redis 才使用壓縮列表來實現(xiàn)字典類型。需要滿足兩個條件:
- 字典中保存的鍵和值的大小都要小于64字節(jié);
- 字典中鍵值對個數(shù)要小于512個。
不能同時滿足上面兩個條件,Redis 就使用散列表來實現(xiàn)字典類型。
-  Redis使用 MurmurHash2 這種運行速度快、隨機性好的哈希算法作為哈希函數(shù)。對于哈希沖突,Redis 使用鏈表法來解決。 
-  Redis還支持散列表的動態(tài)擴容、縮容。當裝載因子 >1 時,Redis會觸發(fā)擴容,將散列表擴大為原來的2倍左右(具體值需要計算得到,感興趣,可以閱讀源碼)。 
-  當裝載因子 < 0.1 的時候,Redis 就會觸發(fā)縮容,縮小為字典中數(shù)據(jù)個數(shù)的大約2倍(這個值也是計算得到的)。 
擴容縮容要做大量的數(shù)據(jù)搬移和哈希值的重新計算,所以比較耗時。Redis 使用漸進式擴容縮容策略,將數(shù)據(jù)搬移分批進行,避免大量數(shù)據(jù)一次性搬移導(dǎo)致的服務(wù)停頓。
4. 集合(set)
集合用來存儲一組不重復(fù)的數(shù)據(jù)。有兩種實現(xiàn)方法,一是基于有序數(shù)組,另一種基于散列表。
- 當要存儲的數(shù)據(jù),同時滿足下面這樣兩個條件的時候,Redis 就采用有序數(shù)組,來實現(xiàn)集合。
- 不能同時滿足這兩個條件時,Redis 使用散列表來存儲集合中的數(shù)據(jù)。
5. 有序集合(sortedset)
有序集合用來存儲一組數(shù)據(jù),并且每個數(shù)據(jù)會附帶一個得分。通過得分大小,將數(shù)據(jù)組織成跳表這樣的數(shù)據(jù)結(jié)構(gòu),以支持快速地按照得分值、得分區(qū)間獲取數(shù)據(jù)。
當數(shù)據(jù)量比較小時,Redis會用壓縮列表來實現(xiàn)有序集合。前提有兩個:
6. 數(shù)據(jù)結(jié)構(gòu)持久化
盡管Redis經(jīng)常會被用作內(nèi)存數(shù)據(jù)庫,但它也支持數(shù)據(jù)落盤,當機器斷電時,存儲在Redis中的數(shù)據(jù)不會丟。重啟后,Redis 只需再將存儲在硬盤中的數(shù)據(jù),重新讀到內(nèi)存,就可以繼續(xù)工作了。
“持久化”,可以籠統(tǒng)地可以理解為“存儲到磁盤"。如何持久化到硬盤?
這種方式也有一定的弊端。那就是數(shù)據(jù)從硬盤還原到內(nèi)存的過程,會耗用較多時間。
比如,將散列表中的數(shù)據(jù)存儲到磁盤。當我們從磁盤中,取出數(shù)據(jù)重新構(gòu)建散列表的時候,需要重新計算每個數(shù)據(jù)的哈希值。
7. 總結(jié)
壓縮列表(可以看作一種特殊的數(shù)組)、有序數(shù)組、鏈表、散列表、跳表。實際上,Redis就是這些常用數(shù)據(jù)結(jié)構(gòu)的封裝。
夯實基礎(chǔ)很重要。基礎(chǔ)很好,不但能知其然,還能知其所以然,從而真正理解Redis作者設(shè)計的動機。不但能有助于我們理解所用的開源軟件,還能為我們自己創(chuàng)新添磚加瓦。
總結(jié)
以上是生活随笔為你收集整理的Redis常用数据类型的数据结构的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: LeetCode 814. 二叉树剪枝(
- 下一篇: spring手动回滚事务_Spring总
