redis 使用addReply系列函数发送查询结果以及错误信息给客户端。这一篇我们来研究redis是如何组织并发送这些消息的。

当网络连接准备好之后redis就会开始等待接收网络数据并处理。

还记得我们在分析createClient这个函数的时候,当conn不为空时的处理吗?

1    if (conn) {
2        connNonBlock(conn);
3        connEnableTcpNoDelay(conn);
4        if (server.tcpkeepalive)
5            connKeepAlive(conn,server.tcpkeepalive);
6        connSetReadHandler(conn, readQueryFromClient);
7...

处理连接请求

还记的我们在讲服务器启动的时候在initServer里面为socket设置Accept事件处理函数的地方吗?

 1    /* Create an event handler for accepting new connections in TCP and Unix
 2     * domain sockets. */
 3    if (createSocketAcceptHandler(&server.ipfd, acceptTcpHandler) != C_OK) {
 4        serverPanic("Unrecoverable error creating TCP socket...

Redis 监听端口

还记得上一篇我们讲的 initServer() 中网络监听的调用吗?

 1    /* Open the TCP listening socket for the user commands. */
 2    if (server.port != 0 &&
 3        listenToPort(server.port,&server.ipfd) == C_ERR) {
 4        serverLog(LL_WARNING, "Failed listening on port %u (TCP), aborting.", server.port);
 5...

redis服务器启动过程

redis经历了长时间的发展,已经从一个简单的内存数据库变为了一个复杂的内存数据库系统。所以启动就包含了很多子系统的初始化过程。我们这里讲启动的流程只能先梳理以下redis启动的脉络,一些子系统的初始化细节还是要放到后续的章节再讲。

redis启动的过程也是redisServer结构初始化的过程,该结构保存了redis server的所有配置信息,我尽量将这个结构中各个字段的用途进行解释如有疏漏还请指正。

入口

redis server的main函数在server.c这个文件中,之前说的redisServer结构保存在server.h中,这个结构足足有500多行,包括指令表、AOF日志、运行时状态、统计数...

skiplist 数据结构

skiplist的数据定义在server.h文件约997行,这个结构比较特别,很奇怪为什么不像其他数据结构一样封装在对应的文件中?

skiplist是zset的实现方式,从名字可以看出其实现的是跳跃表数据结构。跳表的相关数据结构定义如下:

 1/* ZSETs use a specialized version of Skiplists */
 2typedef struct zskiplistNode {
 3    /// 节点名
 4    sds ele;
 5    /// zset中的分
 6    double score;
 7    /// 前序指针
 8    struct...

压缩的双端队列 QuickList

quicklist 作为list指令的底层数据支持,其实现了一个压缩的队列结构。它并非我们常规意义上的链表,而是将整个链表划分成了两层。

  • 第一层使用常规的链表方式,每个节点包含前序和后序指针。
  • 第二层使用ziplist 所以我们在进行插入删除操作的时候,实际上是先找到第一层的链表节点,再在ziplist中查找目标节点的。

quicklist的数据结构:

QuickList

quicklist的创建函...

dict

dict的数据定义如下:

 1/* This is our hash table structure. Every dictionary has two of this as we
 2 * implement incremental rehashing, for the old to the new table. */
 3typedef struct dictht {
 4    dictEntry **table;
 5    unsigned long size;
 6    unsigned long sizemask;
 7    unsigned long used;
 8} dictht;
 9
10...

ziplist

ziplist 作为redis常用的数据结构主要用于小数据量的压缩存储。在数据量较小的情况下,将数据紧凑排列可以有效利用CPU cache,有助于提高缓存命中,让数据读写更加迅速。

ziplist的数据定义很简单,如下:

1/* Each entry in the ziplist is either a string or an integer. */
2typedef struct {
3    /* When string is used, it is provided with the length (slen). */
4    unsigned char *sval;
5    unsigned int...

ADLIST

list 只是普通的链表数据结构,在list结构中保存了dup、free、match三个函数指针用于对链表节点进行复制、释放、查找。 list

 1/* Prototypes */
 2/// 创建链表对象并初始化为一个空链表
 3list *listCreate(void);
 4/// 释放链表
 5void listRelease(list *list);
 6/// 移除所有链表对象
 7void listEmpty(list...