redis的設計與實現:
1.假如有一個用戶關系模塊,要實現一個共同關注功能,計算出兩個用戶關注了哪些相同的用戶,本質上是計算兩個用戶關注集合的交集,如果使用關系數據庫,需要
對兩個數據表執行join操作,對合並的結果執行去重distinct操作,非常復雜
2.Redis直接內置了集合數據類型,支持對集合執行交集/並集/差集等集合計算操作,交集操作可以直接用於共同關注功能,使用之后速度更快代碼量更少,可讀性大大提高
3.越來越多的疑問:五種數據類型是由什么數據結構實現的?字符串數據類型既可以存儲字符串,又可以存儲整數浮點數,二進制位,在內部是怎么存儲這些值的?
有些命令只能對特定數據類型執行,是如何進行類型檢查的?怎樣存儲各種不同類型的鍵值對?過期鍵是怎樣實現自動刪除的?發布與訂閱/腳本/事務等特性是如何實現的?使用什么模型處理客戶端的命令請求?一條命令從發送到返回需要經歷的步驟?
4.第一版發布的時候還不是很完善,作者一邊注釋源碼一邊寫,只介紹了內部機制和單機特性,新版添加了關於二進制位操作/排序/復制/Sentinel和集群等主題的新章節
5.數據結構與對象,單機數據庫的實現,多機數據庫的實現,獨立功能的實現
6.數據庫里面的每個鍵值對都是由對象組成的:數據庫鍵總是字符串對象;鍵的值可以是字符串對象/列表對象(list object)/哈希對象(hash object)/集合對象(set object)/有序集合對象(sorted set object),這五種中的其中一種
7.第一部分和第二部分單機功能比較重要:第一部分,簡單動態字符串,鏈表,字典,跳躍表,整數集合,壓縮列表,對象
8.Redis自己構建了一個SDS的類型用來保存所有的字符串對象,包括鍵值對的鍵,值中存儲字符串對象的底層也是SDS
redis的設計與實現-鏈表
1.鏈表提供了高效的節點重排能力,順序性的節點訪問方式,通過增刪節點調整鏈表的長度,C語言不內置,Redis構建了自己的鏈表實現
2.列表鍵的底層實現之一就是鏈表,當元素比較多,元素都是比較長的字符串,就會使用鏈表作為底層實現
3.發布與訂閱,慢查詢,監視器等功能也用到了鏈表,redis本身使用鏈表保存多個客戶端的狀態信息
4.每個鏈表節點使用adlist.h/listNode結構表示,通過prev和next指針組成雙端鏈表;使用adlist.h/list結構操作更方便,提供了表頭指針head,表尾指針tail,長度計數len,特定類型的函數等
5.鏈表表頭前置和表尾后置都是指向null,所以是無環鏈表,設置不同類型特定函數,可以用於保存不同類型的值
字典
1.字典,又稱為符號表/關聯數組/映射,保存鍵值對的抽象數據結構;一個鍵和一個值進行關聯,或者叫鍵映射為值
2.redis的數據庫就是使用字典作為底層,對數據庫的增刪查改操作也是構建在對字典的操作之上;字典還是哈希鍵的底層實現
3.redis的字典使用哈希表作為底層實現,一個哈希表里面可以有多個哈希表節點,每個哈希表節點保存了字典中的一個鍵值對
4.redis字典所使用的哈希表由dict.h/dictht結構,table屬性是一個數組,每個元素都是指向dict.h/dictEntry結構的指針.每個dictEntry結構保存一個鍵值對
5.哈希表節點使用dictEntry結構表示,key屬性保存着鍵值對中的鍵,v屬性保存着鍵值對中的值,鍵值對的值可以是指針或整數,next屬性是指向另一個哈希表節點的指針,以此解決鍵沖突,通過next指針將兩個索引值相同的鍵k1和k0連接在一起
6.Redis字典由dict.h/dict結構表示,type屬性和privdata屬性是針對不同類型的鍵值對,為創建多態字典設置;ht屬性是一個包含兩個項的數組,每一項都是dictht哈希表,一般只使用ht[0],ht[1]只會在哈希表進行rehash的時候使用,rehashidx記錄rehash的進度
7.哈希算法-將一個新的鍵值對添加到字典里面時,先根據鍵計算出哈希值和索引值,根據索引值將一個新鍵值對的哈希表節點放到哈希表數組的指定索引上
hash=dict->type->hashFunction(key);index=hash&dict->ht[x].sizemask
Redis使用了MurmurHash2算法來計算鍵的哈希值
8.解決鍵沖突,使用了鏈地址法,被分配到同一個索引的多個節點可以用單向鏈表連接起來
9.哈希表保存的鍵值對逐漸增多或者減少,為了讓哈希表的負載因子維持在一個合理的范圍內,程序對大小進行擴展或者收縮
redis的設計與實現-跳躍表
1.跳躍表(skiplist)是一種有序數據結構,通過在每個節點中維持多個指向其他節點的指針,達到快速訪問其他節點的目的,跳躍表支持平均O(logN),最壞O(N)復雜度的節點查找,還可以通過順序性操作批量處理節點
1.跳躍表(skiplist)大部分情況下效率可以和平衡樹媲美,並且比平衡樹要簡單
2.Redis使用跳躍表作為有序集合鍵的底層實現之一,在內部的集群節點中也有使用
3.比如zrange fruit 0 2 withscores 水果名是成員,水果價錢是分數值,每個水果存儲在跳躍表節點中,價錢由低到高排序
4.redis跳躍表由redis.h/zskiplist和redis.h/zskiplistNode兩個結構定義,zskiplist包含,header指向表頭節點,tail指向表尾節點,length跳躍表的長度,level節點中最高層數
zskiplistNode結構包含,level表示層每層都有前進指針和跨度指向下一個節點,backward表示后退指針,score表示分值,obj表示成員對象;遍歷時這些前進指針和后退指針就能啟動快速訪問的目的
5.迭代程序遍歷跳躍表的時候只與前進指針有關,每個層的跨度與節點在跳躍表中的排位有關,每個節點的層高在1-32之間的隨機數