redis4.0的启动流程

简介

redis 在接收客户端连接之前,大概做了以下几件事情:

  1. 初始化服务端配置
  2. 初始化服务器
  3. 进入事件主循环

正文

全局server对象

在redis中,有一个全局的对象server保存了redis服务器对象的信息,redis服务器的操作都围绕着该对象展开。下文中当提及server对象,默认指redis的该全局server对象。

typedef struct redisServer {
pid_t pid; /* Main process pid */
redisDb *db;
aeEventLoop *el; // networking
int port; /* Tcp listening port */
int tcp_backlog;
int ipfd[CONFIG_BINDADDR_MAX]; /* TCP socket file descriptors */
int ipfd_count; /* Used slots in ipfd[] */
char *bindaddr[CONFIG_BINDADDR_MAX]; /* Addresses we should bind to */
int bindaddr_count; /* Number of addresses in server.bindaddr[] */
char neterr[ANET_ERR_LEN]; /* Error buffer for anet.c */
list *clients; /* List of active clients */ /* Limits */
unsigned int maxclients; /* Max number of simultaneous clients */
uint64_t next_client_id; int dbnum; /* Total number of configured DBs */
int verbosity; /* Loglevel in redis.conf */
} redisServer;

初始化配置

redis的入口位于 server.cmain函数,main函数中最为重要的几个函数为initServerConfiginitServer 以及aeMain函数。

int main (int argc, char *argv){
initServerConfig();
initServer();
aeMain(server.el);
}

initServerConfig函数为server对象设置了配置的默认值。这些默认值大多定义在文件server.h中。initServerConfig并不负责分配内存,需要分配内存的操作被放在initServer中执行。

void initServerConfig(void) {
server.port = CONFIG_DEFAULT_SERVER_PORT;
server.bindaddr_count = 0;
server.dbnum = CONFIG_DEFAULT_DBNUM;
server.ipfd_count = 0;
server.maxclients = CONFIG_DEFAULT_MAX_CLIENTS;
server.next_client_id = 1;
}

初始化服务器

initServer函数分配了server对象中clients链表,db数组所需的内存,设置了监听端口,将监听端口的文件描述符在多路复用API中注册。

void initServer(void) {
int j;
server.pid = getpid(); server.clients = listCreate(); // 创建server事件循环所需内存
server.el = aeCreateEventLoop(server.maxclients+128); //监听端口, 此时只调用了 bind 和 listen函数,并将绑定的后的文件描述符传回给server.ipfd数组
if(server.port !=0 &&
listenToPort(server.port, server.ipfd, &server.ipfd_count)== C_ERR)
exit(1); // 为db 分配内存,并为每个db创建对象的dict和过期时间的dict
server.db = zmalloc(sizeof(redisDb)*server.dbnum);
for(j = 0; j < server.dbnum; j++) {
server.db[j].dict = dictCreate(&dbDictType,NULL);
server.db[j].expires = dictCreate(&keyptrDictType,NULL);
server.db[j].id = j;
} for (j = 0; j < server.ipfd_count; j++) {
// 对每个绑定的套接字创建文件事件,对于epoll,是将该文件描述符通过epoll_ctl进行注册
if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE,
acceptTcpHandler,NULL) == AE_ERR){
serverLog(LL_WARNING,
"Unrecoverable error creating server.ipfd file event.");
}
} }

事件主循环

aeMain函数主要处理了多路复用事件的响应, 在没有接受客户端请求之前,服务器实际上一直在等待多路复用API中等待客户端连接TCP的请求。aeProcessEvents函数中调用了aeApiPoll函数,在4.0源码中,一共有4处地方定义了aeApiPoll,具体调用哪个函数,是在编译时提供的变量决定的。

#ifdef HAVE_EVPORT
#include "ae_evport.c"
#else
#ifdef HAVE_EPOLL
#include "ae_epoll.c"
#else
#ifdef HAVE_KQUEUE
#include "ae_kqueue.c"
#else
#include "ae_select.c"
#endif
#endif
#endif

我们可以看作aeApiPoll是对系统函数的一层封装。aeApiPoll函数会将触发事件的文件描述符放入server.eventLoop.fired数组中,并返回触发事件的数量。如果没有时间事件,没有设置超时,并且没有客户端请求触发事件,redis服务器将会一直阻塞。

int aeProcessEvents(aeEventLoop *eventLoop, int flags)
{
int processed = 0, numevents; int j;
struct timeval tv, *tvp; tvp = NULL; /* wait forever */ /* Call the multiplexing API, will return only on timeout or when
* some event fires. */
numevents = aeApiPoll(eventLoop, tvp); for (j = 0; j < numevents; j++) {
aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];
int mask = eventLoop->fired[j].mask;
int fd = eventLoop->fired[j].fd;
int fired = 0; /* Number of events fired for current fd. */ if (!invert && fe->mask & mask & AE_READABLE) {
fe->rfileProc(eventLoop,fd,fe->clientData,mask);
fired++;
} processed++;
} return processed; /* return the number of processed file/time events */
}

对于还未接受客户端请求的服务器,此时接受的是TCP请求连接事件,会接着调用注册在aeFileEvent->rfileProc中的acceptTcpHandler函数。

参考文献

redis 文档

自顶向下redis4.0(1)启动的更多相关文章

  1. 自顶向下redis4.0(3)命令与dict

    redis4.0的命令 简介 目录 redis4.0的命令 简介 正文 redisCommand与redisCommandTable 初始化命令 执行命令 set指令与字典 参考文献 正文 redis ...

  2. 自顶向下redis4.0(2)文件事件与客户端

    redis4.0的文件事件与客户端 目录 redis4.0的文件事件与客户端 简介 正文 准备阶段 接受客户端连接 处理数据 返回数据结果 参考文献 简介 文件事件的流程大概如下: 在服务器初始化时生 ...

  3. 自顶向下redis4.0(5)持久化

    redis4.0的持久化 目录 redis4.0的持久化 简介 正文 rdb持久化 save命令 bgsave命令 rdb定期保存数据 进程结束保存数据 aof持久化 数据缓冲区 刷新数据到磁盘 ap ...

  4. 自顶向下redis4.0(4)时间事件与expire

    redis4.0的时间事件与expire 目录 redis4.0的时间事件与expire 简介 正文 时间事件注册 时间事件触发 expire命令 删除过期键值 被动删除 主动删除/定期删除 参考文献 ...

  5. redis4.0.13主从、哨兵、集群3种模式的 Server端搭建、启动、验证

    本文使用的是redis-4.0.13.tar.gz版本. 两个centos7系统虚拟机:192.168.10.140.192.168.10.150 redis各版本下载地址:http://downlo ...

  6. Redis4.0.0 安装及配置 (Linux — Centos7)

    本文中的两个配置文件可在这里找到 操作系统:Linux Linux发行版:Centos7 安装 下载地址,点这里Redis4.0.0.tar.gz 或者使用命令: wget http://downlo ...

  7. linux 安装redis4.0.6

    1.进入/usr/local/src目录,下载redis # cd /usr/local/src# wget http://download.redis.io/releases/redis-4.0.6 ...

  8. Redis4.0 Cluster — Centos7

    本文版权归博客园和作者吴双本人共同所有 转载和爬虫请注明原文地址 www.cnblogs.com/tdws 一.基础安装 wget http://download.redis.io/releases/ ...

  9. centos6 安装redis-4.0.9

    从redis官网下载Linux redis4.0.9版本,我下载的redis-4.0.9.tar.gz(目前最新稳定版),下载到/usr/local/src目录,如果没有就mkdir创建一个. 下载链 ...

随机推荐

  1. Python3 Socket

    Socket socket介绍 socket意为套接字,是应用层与传输层TCP/IP,UDP之间通信的中间软件抽象层,它是一组接口.使用时只需遵循socket的格式与规定去编程,让socket组织数据 ...

  2. FL Studio进行侧链的三种方式(下)

    在上篇教程中我们了解了在FL Studio中进行侧链的第一种方式,今天我们就来继续带领大家了解进行侧链的另外两种方式. 如何使用 Fruity Peak Controller(果味峰值控制器)在FL ...

  3. 从执行上下文角度重新理解.NET(Core)的多线程编程[2]:同步上下文

    一般情况下,我们可以将某项操作分发给任意线程来执行,但有的操作确实对于执行的线程是有要求的,最为典型的场景就是:GUI针对UI元素的操作必须在UI主线程中执行.将指定的操作分发给指定线程进行执行的需求 ...

  4. acm 易错警示

    1:建图注意是有向图还是无向图,无向开两倍数组 2:看题注意是否为多组输入,多组输入注意初始化. 3:减法取模一定要注意 4:stl中.size()为unsigned如果要计算注意强制类型转换(int ...

  5. NameServer 与zk

    1.nameServer 之间互不通信,故不存在强一致性,即不同的producer看到的视图可能时不一样的,(如何保证最终一致的?) 2.nameServer维护的boker信息 发生变化时,不会像z ...

  6. 5、pgpool-II高可用性(一)数据库的高可用性

    官网示例 一.实现原理 使用 pgpool-II 软件:我们常用来实现流复制的高可用性:备库只读的,不可写:就是当主库出现问题时:需要把备库自动激活为主库:来接管服务. 这在其他高可用软件也有这功能, ...

  7. unittest框架中读取有特殊符号的配置文件内容的方法-configparser的RawConfigParser类应用

    在搭建Unittest框架中,出现了一个问题,配置文件.ini中,出现了特殊字符如何处理? 通过 1.configparser的第三方库对应的ConfigParser类,无法完成对特殊字符的读取: # ...

  8. 【MMT】ICLR 2020: MMT(Mutual Mean-Teaching)方法,无监督域适应在Person Re-ID上性能再创新高

    原文链接 小样本学习与智能前沿 . 在这个公众号后台回复"200708",即可获得课件电子资源. 为了减轻噪音伪标签的影响,文章提出了一种无监督的MMT(Mutual Mean-T ...

  9. MySQL 连接为什么挂死了

    声明:本文为博主原创文章,由于已授权部分平台发表该文章(知乎.云社区),可能造成发布时间方面的困扰. 一.背景 近期由测试反馈的问题有点多,其中关于系统可靠性测试提出的问题令人感到头疼,一来这类问题有 ...

  10. git全流程

    服务器:Ubuntu 使用git前准备工作: 下载git之前先更新: apt-get update 安装git: apt-get install git 创建本地仓库: mkdir test git初 ...