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. [从源码学设计]蚂蚁金服SOFARegistry之程序基本架构

    [从源码学设计]蚂蚁金服SOFARegistry之程序基本架构 0x00 摘要 之前我们通过三篇文章初步分析了 MetaServer 的基本架构,MetaServer 这三篇文章为我们接下来的工作做了 ...

  2. a标签中的target

    html中target四种选择_blank._parent._self._top,分别是什么意思? eg:<Cell title="Open link in new window&qu ...

  3. Linux下Docker容器安装与使用

    注:作者使用的环境是CentOS 7,64位,使用yum源安装. 一.Docker容器的安装 1.查看操作系统及内核版本,CentOS 7安装docker要求系统为64位.系统内核版本为 3.10及以 ...

  4. CLH lock queue的原理解释及Java实现

    目录 背景 原理解释 Java代码实现 定义QNode 定义Lock接口 定义CLHLock 使用场景 运行代码 代码输出 代码解释 CLHLock的加锁.释放锁过程 第一个使用CLHLock的线程自 ...

  5. CENTOS 7平滑升级PHP到最新版7.3

    安装Remi和EPEL数据源(仓库) rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm r ...

  6. 手把手教你使用Vue/React/Angular三大框架开发Pagination分页组件

    DevUI是一支兼具设计视角和工程视角的团队,服务于华为云DevCloud平台和华为内部数个中后台系统,服务于设计师和前端工程师.官方网站:devui.designNg组件库:ng-devui(欢迎S ...

  7. 安装spyder记录

    sudo apt-get install spyder 报错:ERROR: Could not find a version that satisfies the requirement pyqt5& ...

  8. day1(Django)

    1,web项目工作流程 1.1 了解web程序工作流程 1.2 django生命周期   2,django介绍 目的:了解Django框架的作用和特点作用: 简便.快速的开发数据库驱动的网站 Djan ...

  9. 详解Hadoop3.x新特性功能-HDFS纠删码

    文章首发于微信公众号:五分钟学大数据 EC介绍 ​Erasure Coding 简称EC,中文名:纠删码 EC(纠删码)是一种编码技术,在HDFS之前,这种编码技术在廉价磁盘冗余阵列(RAID)中应用 ...

  10. opencv-python imread、imshow浏览目录下的图片文件

    ☞ ░ 前往老猿Python博文目录 ░ 一.几个知识点 1.1.使用Python查找目录下的文件 具体请参考<Python正则表达式re模块和os模块实现文件搜索模式匹配>. 1.2.o ...