如何阅读 Redis 源码

在这篇文章中, 将向大家介绍一种比较合理的 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_epoll.c/ae_evport.c/ae_kqueue.c/ae_select.c。以及任意一个 ae_*.c 文件(取决于你所使用的多路复用库)。Redis 的事件处理器实现(基于 Reactor 模式)。

网路链接库 anet.c和networking.c的网络连接库,负责发送命令回复和接受命令请求, 同时也负责创建/销毁客户端, 以及通信协议分析等工作。

服务器端 redis.c客户端 redis-cli.c

如果读者能完成以上 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 单机功能和多机功能的所有代码了!

其他代码文件介绍

关于测试方面的文件有:

memtest.c     内存检测

redis_benchmark.c     用于redis性能测试的实现。

redis_check_aof.c     用于更新日志检查的实现。

redis_check_dump.c     用于本地数据库检查的实现。

testhelp.c     一个C风格的小型测试框架。

一些工具类的文件如下:

bitops.c     GETBIT、SETBIT 等二进制位操作命令的实现

debug.c     用于调试时使用

endianconv.c     高低位转换,不同系统,高低位顺序不同

help.h     辅助于命令的提示信息

lzf_c.c     压缩算法系列

lzf_d.c     压缩算法系列

rand.c     用于产生随机数

release.c     用于发布时使用

sha1.c sha    加密算法的实现

util.c     通用工具方法

crc64.c     循环冗余校验

sort.c     SORT命令的实现


一些封装类的代码实现:

bio.c     background I/O的意思,开启后台线程用的

latency.c     延迟类

migrate.c     命令迁移类,包括命令的还原迁移等

pqsort.c     排序算法类

rio.c     redis定义的一个I/O类

syncio.c     用于同步Socket和文件I/O操作

下图总结了本文介绍的阅读顺序:



结语

Redis 的设计非常简洁、优美、精巧和高效, 任何人只要愿意去阅读它的代码的话, 应该都会有所收获的。

希望这篇文章能够给想要阅读 Redis 代码的朋友们带来一些帮助, 也欢迎各位随时留言讨论 Redis 源码方面的问题, 或者跟我分享各位阅读 Redis 源码的心得和经验。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容

  • 在这篇文章中, 我将向大家介绍一种我认为比较合理的 Redis 源码阅读顺序, 希望可以给对 Redis 有兴趣并...
    柏树_Jeff阅读 55,713评论 2 18
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,599评论 18 139
  • 超强、超详细Redis入门教程 转载2017年03月04日 16:20:02 16916 转载自: http://...
    邵云涛阅读 17,431评论 3 313
  • 我慢慢从刺耳让人不喜的闹钟声里醒来,但是我不想起床,我也不想把闹钟关掉,我听着它在响,平常我应该做什么了呢。 应该...
    周周昭昭阅读 163评论 0 0
  • 文 | 晨光花开 特别佩服现在的广告运营商。 因为他们已经渗透在我们生活的方方面面。 从手中用的东西,到眼里看的样...
    晨光花开阅读 193评论 0 2