大家好,我是弟弟!最近读了一遍 黄健宏大佬的 <<Redis 设计与实现>>,对Redis 3.0版本有了一些认识,该书作者有一个添加了注释的 redis 3.0源码。
网上说Redis代码写得很好,为了加深印象和学习redis大佬的代码写作艺术,了解工作中使用的redis 命令背后的源码逻辑,便有了从redis命令角度学习redis源码的想法。
从唯一会用的 GET/SET 命令开始 😃
在我们胸有成竹的准备打出GET命令前,我们需要启动一个redis服务器😭,用来接收和处理我们发送的命令 。
(全文提到的redis服务器,都指在 mac os 上启动的一个默认配置的单机redis服务器)
那我们先把redis服务器搞起来
- 在redis 3.0源码中加入各种printf打印调试信息
- sudo make install
- redis-server 启动!
关于redis是单线程的说法
好了,单机redis服务器搞起来了,不禁想起redis是单线程这么一个说法。那这根线程是啥呢,这根线程是一执行就直接returen了吗?显然不是,如果直接就return了,redis服务器启动之后就退出了,那谁来干redis服务器该干的事情😱
嗯,从启动截图来看,这根线程一直在循环,因为没有退出。真是简单直接的原因 😏
那这根线程到底是啥呢?
其实就是redis的main函数。
在 redis.c/main 中可以看到下面的代码,
ae.c/aeMain 当stop为false时,会一直循环下去。
那这根线程在干嘛
- 省略n多细节,来到 redis.c/main里的initServerConfig 初始化服务器相关配置, 比如初始化默认端口 6379
- 省略n多细节,来到 redis.c/main里的initServer 创建并初始化服务器数据结构
- …省略1万字…
- 开启事件处理循环
观众: “emmm… 你tm在逗我,这能说清楚个啥?”
弟弟: “好吧,让我们抛开源码拍一下脑袋,redis起一个线程一直循环,到底在搞什么。”
弟弟: “啊,我想到了。要接受客户端的链接啊!”
观众: “嗯,弟弟想法很不错,居然能想到要接受客户端的链接 😤”
i/o多路复用
没错这根线程干得其中一件事情就是 调用系统函数创建一个i/o对象并拿到文件描述符,读取/处理 客户端的网络连接请求,都跟这个文件描述符有关
这个i/o对象 具体是 select,poll,epoll,kqueue 中的哪一个,取决于编译时的具体操作系统,就像上面说的这是在 mac os 上编译的 redis 3.0 服务器,
可以看到 当前os中 使用的是 kqueue,从这个if/else里可以体现出一个 引入的先后顺序
在上述这4个 7,8年前的 文件 都实现了 aeApiCreate函数,而且不仅实现了这一个,这4个文件里分别实现了一套同名字的 事件处理函数。这个操作可以理解为对事件处理的抽象,在go语言里跟接口的概念很像,这里不禁要说一句🐂🍺。