在這篇文章中, 我將向大家介紹一種我認為比較合理的 Redis 源碼閱讀順序, 希望可以給對 Redis 有興趣并打算閱讀 Redis 源碼的朋友帶來一點幫助。
第 1 步:閱讀數據結構實現
剛開始閱讀 Redis 源碼的時候, 最好從數據結構的相關文件開始讀起, 因為這些文件和 Redis 中的其他部分耦合最少, 并且這些文件所實現的數據結構在大部分算法書上都可以了解到, 所以從這些文件開始讀是最輕松的、難度也是最低的。
下表列出了 Redis 源碼中, 各個數據結構的實現文件:
文件
內容
sds.h
和 sds.c
Redis 的動態字符串實現。
adlist.h
和 adlist.c
Redis 的雙端鏈表實現。
dict.h
和 dict.c
Redis 的字典實現。
redis.h
中的 zskiplist
結構和 zskiplistNode
結構, 以及 t_zset.c
中所有以zsl
開頭的函數, 比如 zslCreate
、 zslInsert
、 zslDeleteNode
,等等。
Redis 的跳躍表實現。
hyperloglog.c
中的 hllhdr
結構, 以及所有以 hll
開頭的函數。
Redis 的 HyperLogLog 實現。
第 2 步:閱讀內存編碼數據結構實現
在閱讀完和數據結構有關的文件之后, 接下來就應該閱讀內存編碼(encoding)數據結構了。
和普通的數據結構一樣, 內存編碼數據結構基本上是獨立的, 不和其他模塊耦合, 但是區別在于:
上一步要讀的數據結構, 比如雙端鏈表、字典、HyperLogLog, 在算法書上或者相關的論文上都可以找到資料介紹。
而內存編碼數據結構卻不容易找到相關的資料, 因為這些數據結構都是 Redis 為了節約內存而專門開發出來的, 換句話說, 這些數據結構都是特制(adhoc)的, 除了 Redis 源碼中的文檔之外, 基本上找不到其他資料來了解這些特制的數據結構。
不過話又說回來, 雖然內存編碼數據結構是 Redis 特制的, 但它們基本都和內存分配、指針操作、位操作這些底層的東西有關, 讀者只要認真閱讀源碼中的文檔, 并在有需要時, 畫圖來分析這些數據結構, 那么要完全理解這些內存編碼數據結構的運作原理并不難, 當然這需要花一些功夫。
下表展示了 Redis 源碼中, 各個內存編碼數據結構的實現文件:
文件
內容
intset.h
和 intset.c
整數集合(intset)數據結構。
ziplist.h
和 ziplist.c
壓縮列表(zip list)數據結構。
第 3 步:閱讀數據類型實現
在完成以上兩個閱讀步驟之后, 我們就讀完了 Redis 六種不同類型的鍵(字符串、散列、列表、集合、有序集合、HyperLogLog)的所有底層實現結構了。
接下來, 為了知道 Redis 是如何通過以上提到的數據結構來實現不同類型的鍵, 我們需要閱讀實現各個數據類型的文件, 以及 Redis 的對象系統文件, 這些文件包括:
文件
內容
object.c
Redis 的對象(類型)系統實現。
t_string.c
字符串鍵的實現。
t_list.c
列表鍵的實現。
t_hash.c
散列鍵的實現。
t_set.c
集合鍵的實現。
t_zset.c
中除 zsl
開頭的函數之外的所有函數。
有序集合鍵的實現。
hyperloglog.c
中所有以 pf
開頭的函數。
HyperLogLog 鍵的實現。
第 4 步:閱讀數據庫實現相關代碼
在讀完了 Redis 使用所有底層數據結構, 以及 Redis 是如何使用這些數據結構來實現不同類型的鍵之后, 我們就可以開始閱讀 Redis 里面和數據庫有關的代碼了, 它們分別是:
文件
內容
redis.h
文件中的 redisDb
結構, 以及 db.c
文件。
Redis 的數據庫實現。
notify.c
Redis 的數據庫通知功能實現代碼。
rdb.h
和 rdb.c
Redis 的 RDB 持久化實現代碼。
aof.c
Redis 的 AOF 持久化實現代碼。
選讀
Redis 有一些獨立的功能模塊, 這些模塊可以在完成第 4 步之后閱讀, 它們包括:
文件
內容
redis.h
文件的 pubsubPattern
結構,以及 pubsub.c
文件。
發布與訂閱功能的實現。
redis.h
文件的 multiState
結構以及 multiCmd
結構, multi.c
文件。
事務功能的實現。
sort.c
SORT
命令的實現。
bitops.c
GETBIT
、 SETBIT
等二進制位操作命令的實現。
第 5 步:閱讀客戶端和服務器的相關代碼
在閱讀完數據庫實現代碼, 以及 RDB 和 AOF 兩種持久化的代碼之后, 我們可以開始閱讀客戶端和 Redis 服務器本身的實現代碼, 和這些代碼有關的文件是:
文件
內容
ae.c
,以及任意一個 ae_*.c
文件(取決于你所使用的多路復用庫)。
Redis 的事件處理器實現(基于 Reactor 模式)。
networking.c
Redis 的網絡連接庫,負責發送命令回復和接受命令請求, 同時也負責創建/銷毀客戶端, 以及通信協議分析等工作。
redis.h
和 redis.c
中和單機 Redis 服務器有關的部分。
單機 Redis 服務器的實現。
如果讀者能完成以上 5 個閱讀步驟的話, 那么恭喜你, 你已經了解了單機的 Redis 服務器是怎樣處理命令請求和返回命令回復, 以及是 Redis 怎樣操作數據庫的了, 這是 Redis 最重要的部分, 也是之后繼續閱讀多機功能的基礎。
選讀
Redis 有一些獨立的功能模塊, 這些模塊可以在完成第 5 步之后閱讀, 它們包括:
文件
內容
scripting.c
Lua 腳本功能的實現。
slowlog.c
慢查詢功能的實現。
monitor.c
監視器功能的實現。
第 6 步:閱讀多機功能的實現
在弄懂了 Redis 的單機服務器是怎樣運作的之后, 就可以開始閱讀 Redis 多機功能的實現代碼了, 和這些功能有關的文件為:
文件
內容
replication.c
復制功能的實現代碼。
sentinel.c
Redis Sentinel 的實現代碼。
cluster.c
Redis 集群的實現代碼。
注意, 因為 Redis Sentinel 用到了復制功能的代碼, 而集群又用到了復制和 Redis Sentinel 的代碼, 所以在閱讀這三個模塊的時候, 記得先閱讀復制模塊, 然后閱讀 Sentinel 模塊, 最后才閱讀集群模塊, 這樣理解起來就會更得心應手。
如果你連這三個模塊都讀完了的話, 那么恭喜你, 你已經讀完了 Redis 單機功能和多機功能的所有代碼了!
下圖總結了本文介紹的閱讀順序:
encoding_datastruct -> object -> db -> client_and_server -> multi_server}" style="border: 0px; max-width: 100%;">
結語
Redis 的設計非常簡潔、優美、精巧和高效, 任何人只要愿意去閱讀它的代碼的話, 應該都會有所收獲的。
希望這篇文章能夠給想要閱讀 Redis 代碼的朋友們帶來一些幫助, 也歡迎各位隨時和我討論 Redis 源碼方面的問題, 或者跟我分享各位閱讀 Redis 源碼的心得和經驗。
另外我的 Redis 源碼注釋 項目以及 《Redis 設計與實現》 一書對于理解 Redis 的源代碼應該也會有所幫助, 有興趣的朋友可以自行了解該項目/書本。