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