Redis源码解析(1)——源码目录介绍

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 概念      redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)和zset(有序集合)。

概念

      redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)和zset(有序集合)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

 

开始

      这里我使用的是redis-2.2.2.tar.gz版本的redis(下载地址)首先要对它进行安装,这里我选择使用cygwin工具进行安装,加入我把该压缩包放在F盘下,使用cygwin工具进行shell命令:

1
2
3
tar  xzf redis-2.2.2. tar .gz
cd  redis-2.2.2
make

     这里的make实际上操作的是Makefile文件,Makefile按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个shell脚本一样,其中也可以执行操作系统的命令。

浏览下Redis根目录中的Makefile文件:

      通过make命令可以执行“cd src && make all”。而此时的make all实际上已经开始执行src目录中的Makefile文件。这个文件比较复杂,大致就是将一系列的c文件以及h文件链接起来,通过cc/gcc编译器将文件生成目标文件o,接着将相应的o目标文件在通过编译器生成exe文件,当你编译完毕后,在src的目录上将产生5个exe文件:

image

redis-benchmark.exe:用于做性能测试;

redis-check-aof.exe:更新日志检查;

redis-check-dump.exe:用于本地数据库检查;

redis-cli.exe:客户端程序;

redis-server.exe:服务端程序;

具体用法这里不多说了,可以参考(http://www.cnblogs.com/daizhj/articles/1956681.html

 

      现在来看下src包含的文件(我按照首字母顺序来讲):

adlist.h/adlist.c:用于对list的定义,它是个双向链表结构,从头文件可以找到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// list节点
typedef  struct  listNode {
     struct  listNode *prev;
     struct  listNode *next;
     void  *value;
} listNode;
 
// list迭代器
typedef  struct  listIter {
     listNode *next;
     int  direction;
} listIter;
 
// list数据结构
typedef  struct  list {
     listNode *head;
     listNode *tail;
     void  *(*dup)( void  *ptr);
     void  (* free )( void  *ptr);
     int  (*match)( void  *ptr,  void  *key);
     unsigned  int  len;
} list;

在ListNode节点下包含prev指针和next指针,说明它通过指针将节点进行双向链接。

并且从adlist.h的头文件可以找到非常丰富的方法声明,包括list创建,list释放,list头部/尾部添加节点等等,具体在后面的系列会做出介绍。

 

ae.h/ae.c:用于Redis的事件处理,包括句柄事件和超时事件。

在ae.c中的头部可以发现:

1
2
3
4
5
6
7
8
9
#ifdef HAVE_EPOLL
#include "ae_epoll.c"
#else
     #ifdef HAVE_KQUEUE
     #include "ae_kqueue.c"
     #else
     #include "ae_select.c"
     #endif
#endif

      在网络相关操作中,定义了一组公共操作接口:aeApiCreate,aeApiFree,aeApiAddEvent,aeApiDelEvent,aeApiPoll,aeApiName方法。在ae_epoll.c、ae_kqueue.c和ae_select.c中,分别实现了基于epoll/kqueue和select系统调用的接口。系统调用的选择顺序依次为epoll,kqueue,select。

 

anet.h/anet.c:这两个文件非常重要,作为Server/Client通信的基础封装,包括anetTcpServer,anetTcpConnect,anetTcpAccept,anetRead,anetWrite等等方法。

 

aof.c:aof,全称为append only file,作用就是记录每次的写操作,在遇到断电等问题时可以用它来恢复数据库状态。但是他不是bin的,而是text的。一行一行,写得很规范.如果你是一台redis,那你也能人肉通过它恢复数据。

 

config.h/config.c:用于将配置文件redis.conf文件中的配置读取出来的属性通过程序放到server对象中。在main函数(server服务主入口点处)可以发现里面调用loadServerConfig(char *filename)方法,这个方法就是使用config.c里面的方法实现。具体会在后面的系列中详细介绍。

 

db.c:对于Redis内存数据库的相关操作。

 

debug.c:用于调试使用。

 

dict.h/dict.c:也是很重要的两个文件,主要对于内存中的hash进行管理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
typedef  struct  dictEntry {
     void  *key;
     void  *val;
     struct  dictEntry *next;
} dictEntry;
 
typedef  struct  dictType {
     unsigned  int  (*hashFunction)( const  void  *key);
     void  *(*keyDup)( void  *privdata,  const  void  *key);
     void  *(*valDup)( void  *privdata,  const  void  *obj);
     int  (*keyCompare)( void  *privdata,  const  void  *key1,  const  void  *key2);
     void  (*keyDestructor)( void  *privdata,  void  *key);
     void  (*valDestructor)( void  *privdata,  void  *obj);
} dictType;
typedef  struct  dict {
     dictType *type;
     void  *privdata;
     dictht ht[2];
     int  rehashidx;  /* rehashing not in progress if rehashidx == -1 */
     int  iterators;  /* number of iterators currently running */
} dict;

这里dictEntry作为一个dict字段结构,里面包括key以及value,已经指向下一个dictEntry的指针。dictType作为一些dict的操作结构。dict作为一个hash结构。后面的文章会具体介绍。

 

fmacros.h:用于Mac下的兼容性处理。

 

help.h:辅助于命令的提示信息,作用于redis-cli.exe可执行文件中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct  commandHelp {
   char  *name;
   char  *params;
   char  *summary;
   int  group;
   char  *since;
} commandHelp[] = {
     "APPEND" ,
     "key value" ,
     "Append a value to a key" ,
     1,
     "1.3.3"  },
     "AUTH" ,
     "password" ,
     "Authenticate to the server" ,
     8,
     "0.08"  },
     "BGREWRITEAOF" ,
     "-" ,
     "Asynchronously rewrite the append-only file" ,
     9,
     ....
};

 

intset.h/intset.c:整数范围内的使用set,并包含相关set操作。

 

lzf.h/lzf_c.c/lzf_d.c/lzfP.h:对于本地数据库的保存,使用的是LZF压缩算法,很神奇,算法只有200-300行的代码。

 

multi.c:用于事务处理操作。请看这样的一个例子:

image

通过执行exec,可以提交整个事务过程,如果你想撤销整个事务过程,你可以使用discard命令:

image

可以发现get age已经取不到值了,说明discard命令让事务失效。

 

networking.c:网络协议传输方法定义相关的都放在这个文件里面了。包括让Client连接上Server,让Slave挂接到Master,已经Server/Client之间的信息交互的实现等等。

 

object.c:用于创建和释放redisObject对象,redisObject结构为:

1
2
3
4
5
6
7
8
9
10
11
12
typedef  struct  redisObject {
     unsigned type:4;
     unsigned storage:2;      /* REDIS_VM_MEMORY or REDIS_VM_SWAPPING */
     unsigned encoding:4;
     unsigned lru:22;         /* lru time (relative to server.lruclock) */
     int  refcount;
     void  *ptr;
     /* VM fields are only allocated if VM is active, otherwise the
      * object allocation function will just allocate
      * sizeof(redisObjct) minus sizeof(redisObjectVM), so using
      * Redis without VM active will not have any overhead. */
} robj;

 

pqsort.h/pqsort.c/sort.c:关于排序算法,sort.c具体作为Redis场景下的排序实现。

 

pubsub.c:用于订阅模式的实现,有点类似于Client广播发送的方式。

 

rdb.c:对于Redis本地数据库的相关操作,默认文件是dump.rdb(通过配置文件获得),包括的操作包括保存,移除,查询等等。

 

redis-benchmark.c:用于redis性能测试的实现。请看main方法以下设置:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
config.debug = 0;
config.numclients = 50;
config.requests = 10000;
config.liveclients = 0;
config.el = aeCreateEventLoop();
aeCreateTimeEvent(config.el,1,showThroughput,NULL,NULL);
config.keepalive = 1;
config.donerequests = 0;
config.datasize = 3;
config.randomkeys = 0;
config.randomkeys_keyspacelen = 0;
config.quiet = 0;
config.loop = 0;
config.idlemode = 0;
config.latency = NULL;
config.clients = listCreate();
config.hostip =  "127.0.0.1" ;
config.hostport = 6379;
config.hostsocket = NULL;
 
parseOptions(argc,argv);
config.latency = zmalloc( sizeof ( long  long )*config.requests);

默认性能测试中的客户端数量为50个,并行发送的请求有10000条,你也可以通过redis-benchmark命令行参数进行设置。

 

redis-check-aof.c:用于更新日志检查的实现。

 

redis-check-dump.c:用于本地数据库检查的实现。

 

redis-cli.c:客户端程序的实现。具体会在后面的文章详细介绍。

 

redis.h/redis.c:服务端程序的实现。具体会在后面的文章详细介绍。

 

release.h/release.c:用于发布使用。

 

replication.c:用于主从数据库的复制操作的实现。


sds.h/sds.c:用于对字符串的定义,从头文件可以找到:

1
2
3
4
5
6
//字符串
struct  sdshdr {
     int  len;
     int  free ;
     char  buf[];
};

还可以看到对于字符串的相关操作,包括复制,连接,清零等等。

 

sha1.h/sha1.c:有关于sha算法的实现。

 

solarisfixes.h:Solaris系统的兼容性实现。

 

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

 

t_hash.c/t_list.c/t_set.c/t_string.c/t_zset.c:hash,list,set,string,zset在Server/Client中的应答操作。主要通过redisObject进行类型转换。

 

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

 

util.c:关于通用工具的方法实现。

 

version.h:Redis版本号定义。

 

vm.c:关于虚拟内存的管理实现。

 

zipmap.h/zipmap.c:zipmap是一个类似于hash的存储对象。在新建一个hash对象时开始是用zipmap(又称为small hash)来存储的。这个zipmap其实并不是hash table但是zipmap相比正常的hash实现可以节省不少hash本身需要的一些元数据存储开销,如果field或者value的大小超出一定限制后,redis会在内部自动将zipmap替换成正常的hash实现。

 

ziplist.h/ziplist.c:ziplist是一个类似于list的存储对象。它的原理类似于zipmap。

 

zmalloc.h/zmalloc.c:关于Redis的内存分配的封装实现。

 

 

下一篇我会介绍下redis-server以及redis-cli的源码实现。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
9天前
|
NoSQL Linux Redis
06- 你们使用Redis是单点还是集群 ? 哪种集群 ?
**Redis配置:** 使用哨兵集群,结构为1主2从,加上3个哨兵节点,总计分布在3台Linux服务器上,提供高可用性。
18 0
|
17天前
|
负载均衡 监控 NoSQL
Redis的集群方案有哪些?
Redis集群包括主从复制(基础,手动故障恢复)、哨兵模式(自动高可用)和Redis Cluster(官方分布式解决方案,自动分片和容错)。此外,还有如Codis、Redisson和Twemproxy等第三方工具用于代理和负载均衡。选择方案需考虑应用场景、数据规模和并发需求。
17 2
|
23天前
|
NoSQL Redis
Redis集群(六):集群常用命令及说明
Redis集群(六):集群常用命令及说明
15 0
|
2月前
|
运维 NoSQL 算法
Redis-Cluster 与 Redis 集群的技术大比拼
Redis-Cluster 与 Redis 集群的技术大比拼
46 0
|
17天前
|
NoSQL Java 测试技术
面试官:如何搭建Redis集群?
**Redis Cluster** 是从 Redis 3.0 开始引入的集群解决方案,它分散数据以减少对单个主节点的依赖,提升读写性能。16384 个槽位分配给节点,客户端通过槽位信息直接路由请求。集群是无代理、去中心化的,多数命令直接由节点处理,保持高性能。通过 `create-cluster` 工具快速搭建集群,但适用于测试环境。在生产环境,需手动配置文件,启动节点,然后使用 `redis-cli --cluster create` 分配槽位和从节点。集群动态添加删除节点、数据重新分片及故障转移涉及复杂操作,包括主从切换和槽位迁移。
29 0
面试官:如何搭建Redis集群?
|
21天前
|
存储 缓存 NoSQL
【Redis深度专题】「核心技术提升」探究Redis服务启动的过程机制的技术原理和流程分析的指南(集群功能分析)(一)
【Redis深度专题】「核心技术提升」探究Redis服务启动的过程机制的技术原理和流程分析的指南(集群功能分析)
41 0
|
1月前
|
NoSQL Redis Docker
使用Docker搭建一个“一主两从”的 Redis 集群(超详细步骤)
使用Docker搭建一个“一主两从”的 Redis 集群(超详细步骤)
45 0
|
1月前
|
存储 监控 NoSQL
Redis 架构深入:主从复制、哨兵到集群
大家好,我是小康,今天我们来聊下 Redis 的几种架构模式,包括主从复制、哨兵和集群模式。
Redis 架构深入:主从复制、哨兵到集群
|
1月前
|
运维 负载均衡 NoSQL
【大厂面试官】知道Redis集群和Redis主从有什么区别吗
集群节点之间的故障检测和Redis主从中的哨兵检测很类似,都是通过PING消息来检测的。。。面试官抓抓脑袋,继续看你的简历…得想想考点你不懂的😰。
67 1
|
1月前
|
缓存 NoSQL Java
Redis缓存高可用集群
Redis缓存高可用集群

热门文章

最新文章