Redis源码阅读【1-简单动态字符串】
Redis源码阅读【2-跳跃表】
Redis源码阅读【3-Redis编译与GDB调试】
Redis源码阅读【4-压缩列表】
Redis源码阅读【5-字典】
Redis源码阅读【6-整数集合】
Redis源码阅读【7-quicklist】
Redis源码阅读【8-命令处理生命周期-1】
Redis源码阅读【8-命令处理生命周期-2】
Redis源码阅读【8-命令处理生命周期-3】
Redis源码阅读【8-命令处理生命周期-4】
Redis源码阅读【番外篇-Redis的多线程】
建议搭配源码阅读:源码地址
本章主要是为了介绍Redis的编译方式,以及使用GDB对Redis进行调试的方法,为后面讲解源码打下基础,同时也介绍GDB这个C语言代码调试利器的部分使用
Redis编译应该是一个必须掌握的技能,毕竟很多时候我们并不一定会直接使用Redis编译好的包类型,可能会更具当前操作系统的情况,调整部分源码编译后再使用,例如Redis5当前的版本是不支持Windows的,如果大家想要使用Windows版本的Redis最好去官网下载Redis3以及之前的版本去自行编译使用,此外当大家希望能在Redis中加入一些日志或者其它东西的时候,一样需要修改源码进行编译,那么下面就介绍一下官方的推荐的编译步骤(很简单的)
自行编译的第一步当然就算获取源码,Redis获取源码的方式最直接的就是github,这里我贴出Redis的github地址:https://github.com/antirez/redis,或者你可以通过github搜索Redis:
当然github上面的是最新版本的代码,并非稳定版本代码,许多新版本的特性会先在github中放出,让大家下载调试体验,当然线上稳定版本还是建议去官网下载Stable版本,地址:https://redis.io/download
其中这个antirez/redis就是Redis在github上面官方的地址了。下载好后源码,我们可以随便导入到一个IDE里面查看,这里我使用的是Clion
项目结构如上图所示:
目录/文件 | 说明 |
---|---|
deps | Hiredis 模块(轻量级访问redis的客户端),linenoise模块(命令行编辑辅助,能实现自动补全) ,字典的定义实现,sds的定义实现,redis封装的malloc,Lua等 |
src | 核心源码,大多功能都在这块实现,其中Redis自行实现了网络框架在这个目录中(ae_开头的文件),Redis并未使用libevent作为网络模块 |
tests | 测试模块,用来测试Redis的代码,大多测试用例和脚本都在这里面 |
utils | Redis的工具实现 |
redis.conf | Redis官方源码默认提供的配置文件 |
Makefile | Redis C语言编译使用的Makefile,当然你也可以使用Cmake进行管理,当然Cmake支持的不是很好 |
在编译前,我们需要进行一些准备工作,我们本人是在Ubuntu-18上面进行编译的,Linux环境是推荐环境,Redis5目前只适配了Linux,并没有适配Windows,那么在Linux上进行编译本身我们也需要准备和更新一些内库,这里我当且认为你已经按照好了Ubuntu
1、更新Ubuntu到最新版本
sudo apt update
更新系统自带内库等等
2、下载编译必备内库,内包含一些C/C++必备的库
sudo apt install build-essential
sudo apt install gcc-c++
3、除此外可能会使用到的内库
apt-get install libqt4-* libqml*
4、如果出现has no member named(这个问题是由于官方升级了gcc导致的)
升级到 5.3及以上版本
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
//这里退出xhell会恢复gcc版本
scl enable devtoolset-9 bash
//永久替换
echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile
5、安装测试工具tcl
sudo apt install tcl
一切准备好后,准备开始编译,进入到源码目录底下,项目的根目录
直接编译
make #直接编译
make MALLOC=libc # 指定使用 libc对 malloc 编译
make MALLOC=jemalloc # 指定使用 jemalloc 编译但是要先安装jemalloc依赖
当然你也可以编译成32位版本
make 32bit
执行后结果如下:
这里会提示你需要使用 make test 来执行内部的自测用例(test文件夹里面),来判断本次编译是否完全成功
执行 make test
sudo apt install tcl # 需要先安装tcl
make test
过程如下:
当出现这句化的时候证明自测已经成功
All tests passed withour errors!
这个时候进入项目根目录底下的src目录中你会发现几个已经编译好的二进制文件,是可以直接运行的
这两个就是服务端和客户端的运行入口了,其中默认的配置文件在外层根目录(redis.conf)
运行 ./redis-server 或者 ./redis-server …/redis.conf
./redis-server
结果如下
这个时候Redis服务端已经运行起来了。我们再打开一个终端,运行下面的指令:
root@zengshilin-virtual-machine:/home/test/redis-5.0.7/src# ./redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> set test hello
OK
127.0.0.1:6379> get test
"hello"
到这里我们的Redis已经完全编译成功了
GDB是unix/linux的常用调试工具,其中GDB支持man手册查阅,在Liunx这种经常没有可视化界面的操作系统底下,GDB是一种经常使用的调试工具,那么这里我也推荐大家使用GDB来调试已经编译好的Redis代码,其中Redis官网对GDB的介绍如下:http://redis.io/topics/debugging
可见官方也是推荐GDB来调试Redis
在Ubuntu底下安装GDB使用这条指令即可
sudo apt-get install gdb
进入到刚刚编译好的Redis目录src底下,输入指令:
gdb redis-server
结果如下:
此时刚刚编译好的redis-server已经进入到gdb的调试模式下,但是当前还未运行,然后我们启动以下redis服务端,使用 r 或者 r …/redis.conf
(gdb) r ../redis.conf
可以看到当前的Redis在GDB调试模式下启动了,这个使用我们再开一个新的窗口运行redis-cli查看效果如下:
127.0.0.1:6379> set test hello
OK
127.0.0.1:6379> get test
"hello"
127.0.0.1:6379> keys *
1) "test"
127.0.0.1:6379>
可见服务端当前也是可用状态的
GDB个其它调试一样,可以打断点在目标代码上面,同时也支持单步调试等操作,我们在服务断t_string.c文件上面的set命令打上断点看看是否生效,代码位置如图所示:
我们将断点打在setCommand上面,在gdb模式下执行:
(gdb) b setCommand
Breakpoint 1 at 0x609c0: file t_string.c, line 96.
断点已经打好,这时候我们在gdb模式下启动Redis
(gdb) r ../redis.conf
然后我们打开一个新终端,运行 redis-cli 输入以下命令
127.0.0.1:6379> set test hello
可以看到服务断那边已经执行到断点的位置
这时我们查看以下redis的运行栈
了解计算机操作系统的同学应该都知道,程序调用是基于栈的,所以这里打印出当前线程运行所经历的调用栈
我们通过以下指令来尝试GDB调试:
(gdb) n # 单步执行
102 for (j = 3; j < c->argc; j++) {
(gdb) n
100 int flags = OBJ_SET_NO_FLAGS;
(gdb) n
99 int unit = UNIT_SECONDS;
(gdb) n
98 robj *expire = NULL;
(gdb) n
138 c->argv[2] = tryObjectEncoding(c->argv[2]);
(gdb) s # 进入函数内部
tryObjectEncoding (o=0x7ffff6c0e0c0) at object.c:431
431 robj *tryObjectEncoding(robj *o) {
(gdb) p *o # p 是 print的意思 打印当前变量
$1 = {type = 0, encoding = 8, lru = 454090, refcount = 1, ptr = 0x7ffff6c0e0d3}
(gdb) p o->type # 打印变量的成员属性
$2 = 0
(gdb)
以上就算GDB调试的大致用法,也介绍大家可以多去官网看看gdb的其它使用技巧:http://www.gnu.org/software/gdb/
这篇文章我们介绍了Redis在linux低下使用源码编译的过程,以及如何使用GDB调试工具来断点调试已经编译好的Redis,后续文章我也会不时使用GDB的方式来调试Redis的代码运行过程,以便更好的理解Redis的源码执行过程。