memcached源码分析-----安装、调试以及如何阅读memcached源码
安装:
安装memcached之前要先安装Libevent。现在假定Libevent安装在/usr/local/libevent目录了。
因为memcached安装后不像Libevent那样,有一堆头文件和库文件。安装后的memcached不是用来编程而直接用来运行的。所以不需要在/usr/local目录下专门为memcached建立一个目录。直接把memcached安装到/usr/local即可。
在Linux中解压memcached-1.4.21.tar.gz,然后进入解压后的目录。输入命令下面命令进行配置安装。
$./configure --with-libevent=/usr/local/libevent
$make
$sudo make install
memcached的默认安装目录就是/usr/local,如果想安装在自己的目录,那么可以configure的时候用--prefix=xxx指定一个目录。--with-libevent就是用来指明Libevent的安装目录的。
如果安装目录是/usr/local那么现在可以memcached这个可执行程序了,直接在命令行输入memcached即可,并且此时可以使用命令$man memcached查询帮助手册。
假如是安装在其他目录,比如/usr/local/memcached目录,那么还需要一些配置。首先要配置可执行文件的查找目录,需要修改PATH环境变量。在/etc/bash.bashrc文件最后添加:
exportPATH=$PATH:/usr/local/memcached/bin
此时,就可以在shell中能运行memcached命令了。但还不能使用man来查询memcached的帮助手册。因为该命令的帮助手册没有在man的查询目录上。在/usr/local/memcached/share/man/man1目录中,有一个memcached.1文件。把这个文件拷贝到/usr/local/share/man/man1目录下。此时就可以man 这个memcached了。
调试:
如果已经安装了memcached,那么先使用$sudo make uninstall命令进行卸载。configure 配置和前面一样,不需要改变。然后输入下面命令生成debug版本的memcached。
$make CFLAGS="-g -O0"
$sudo make install
这样就行了。然后直接是shell里面输入$gdb memcached命令启动memcached。至于memcached的参数是在启动gdb之后,使用run命令的时候才输入的。如下图所示:
要记得先设置断点,然后才使用r或者run命令。
启动命令:
简单的启动命令如下,设置-l和-p分别用来设置ip和监听的端口。-vv是输出一些运行信息。
$memcached -l 192.168.1.112 -p 8888 -vv
和libevent的关系:
memcached依赖于libevent。从memcached的编译就可以知道。阅读memcached的代码需要懂得libevent的基本使用,关于libevent的使用例子可以参考《Libevent使用例子,从简单到复杂》。当然阅读memcached源码并不需要阅读libevent源码作为基础,懂得libevent的基本使用即可。假如读者想阅读libevent的源代码,可以参考《libevent源码分析》系列文章。
和libevent源码阅读的难度比较:
虽然memcached的代码量比libevent少很多,但阅读起来却比libevent难很多。主要原因有:memcached使用了大量的全局变量;各个模块之间的关联性很强;使用了大量的锁和很多线程。而libevent的各个模块独立得比较好,模块间关联很少,基本上是各个模块完成自己独立的功能,然后向外界提供使用接口。所以阅读memcached的代码更要耐心。另外,阅读memcached源码除了需要会用libevent外还需要懂得多线程、socket、管道等等东西的基本使用。当然如果看过《UNIX环境高级编程》那么就没有问题了。
如何阅读memcached源代码:
1.找一篇概括性描述memcached的文章。了解memcached使用了哪些技术以及memcached内部的各个模块(比如内部有哈希表、slab内存分配器、LRU队列、半同步半异步等等)。一个日本人写的《memcached完全剖析》可以看一下,里面并没有涉及到代码只是简单介绍memcached。
2.分模块阅读代码,可以单独阅读slabs.c文件、assoc.c文件、items.c文件。看完一个模块的基本功能后,再阅读另外一个模块的。记住,不要想一次就把整个模块完全看懂。memcached模块间关联太大的,不可能一次性看懂的。要经常回过头看之前看过的模块,特别是看到了一些相关联的东西(比如全局变量)。
3.虽然分模块阅读会容易一些,但对于memcached来说还是有点难度。因为memcached模块之间的关联比较大,不像libevent分得那么开。关联一般是通过一些全局变量。但memcached使用了很多很多很多全局变量,所以阅读代码的时候要注意全局变量是否有static修饰符(如果有的话就心里暗喜吧)。另外,在阅读某一个模块的时候,要假设这些全局变量取默认值并且不会变,这样阅读起来会容易一点。相当部分的全局变量是结构体变量settings的成员变量。全局变量settings的很多成员都可以在启动memcached的时候通过参数设置,但阅读的时候就假定没有设置。全部成员都取默认值。settings_init函数是用来给全局变量settings的各个成员赋默认值的。每次阅读代码的时候建议都打开这个函数方便随时查看各个成员的默认值。
4.memcached使用了大量的锁和多个线程(非worker线程),阅读时不要理会这些锁和线程。看到锁就跳过,假定没有锁是线程安全的。对于那些非worker线程,就假定没有这个线程。哈哈!
5.有一些功能是要开启才有的,比如LRU爬虫功能。在阅读代码的时候就假设没有开启这个功能。这个功能一般是通过全局变量的值而决定开启还是不开启的。那么在看到这个全局变量时,就直接把其取为不开启的值。
至于代码的阅读顺序,可以参考本系列博文的写作顺序。简单来说就是从简单到复杂、从单一的结构到总体。
延伸阅读