自顶向下redis4.0(1)启动
redis4.0的启动流程
简介
redis 在接收客户端连接之前,大概做了以下几件事情:
- 初始化服务端配置
- 初始化服务器
- 进入事件主循环
正文
全局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.c 的main函数,main函数中最为重要的几个函数为initServerConfig,initServer 以及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函数。
参考文献
自顶向下redis4.0(1)启动的更多相关文章
- 自顶向下redis4.0(3)命令与dict
redis4.0的命令 简介 目录 redis4.0的命令 简介 正文 redisCommand与redisCommandTable 初始化命令 执行命令 set指令与字典 参考文献 正文 redis ...
- 自顶向下redis4.0(2)文件事件与客户端
redis4.0的文件事件与客户端 目录 redis4.0的文件事件与客户端 简介 正文 准备阶段 接受客户端连接 处理数据 返回数据结果 参考文献 简介 文件事件的流程大概如下: 在服务器初始化时生 ...
- 自顶向下redis4.0(5)持久化
redis4.0的持久化 目录 redis4.0的持久化 简介 正文 rdb持久化 save命令 bgsave命令 rdb定期保存数据 进程结束保存数据 aof持久化 数据缓冲区 刷新数据到磁盘 ap ...
- 自顶向下redis4.0(4)时间事件与expire
redis4.0的时间事件与expire 目录 redis4.0的时间事件与expire 简介 正文 时间事件注册 时间事件触发 expire命令 删除过期键值 被动删除 主动删除/定期删除 参考文献 ...
- redis4.0.13主从、哨兵、集群3种模式的 Server端搭建、启动、验证
本文使用的是redis-4.0.13.tar.gz版本. 两个centos7系统虚拟机:192.168.10.140.192.168.10.150 redis各版本下载地址:http://downlo ...
- Redis4.0.0 安装及配置 (Linux — Centos7)
本文中的两个配置文件可在这里找到 操作系统:Linux Linux发行版:Centos7 安装 下载地址,点这里Redis4.0.0.tar.gz 或者使用命令: wget http://downlo ...
- linux 安装redis4.0.6
1.进入/usr/local/src目录,下载redis # cd /usr/local/src# wget http://download.redis.io/releases/redis-4.0.6 ...
- Redis4.0 Cluster — Centos7
本文版权归博客园和作者吴双本人共同所有 转载和爬虫请注明原文地址 www.cnblogs.com/tdws 一.基础安装 wget http://download.redis.io/releases/ ...
- centos6 安装redis-4.0.9
从redis官网下载Linux redis4.0.9版本,我下载的redis-4.0.9.tar.gz(目前最新稳定版),下载到/usr/local/src目录,如果没有就mkdir创建一个. 下载链 ...
随机推荐
- Python3 Socket
Socket socket介绍 socket意为套接字,是应用层与传输层TCP/IP,UDP之间通信的中间软件抽象层,它是一组接口.使用时只需遵循socket的格式与规定去编程,让socket组织数据 ...
- FL Studio进行侧链的三种方式(下)
在上篇教程中我们了解了在FL Studio中进行侧链的第一种方式,今天我们就来继续带领大家了解进行侧链的另外两种方式. 如何使用 Fruity Peak Controller(果味峰值控制器)在FL ...
- 从执行上下文角度重新理解.NET(Core)的多线程编程[2]:同步上下文
一般情况下,我们可以将某项操作分发给任意线程来执行,但有的操作确实对于执行的线程是有要求的,最为典型的场景就是:GUI针对UI元素的操作必须在UI主线程中执行.将指定的操作分发给指定线程进行执行的需求 ...
- acm 易错警示
1:建图注意是有向图还是无向图,无向开两倍数组 2:看题注意是否为多组输入,多组输入注意初始化. 3:减法取模一定要注意 4:stl中.size()为unsigned如果要计算注意强制类型转换(int ...
- NameServer 与zk
1.nameServer 之间互不通信,故不存在强一致性,即不同的producer看到的视图可能时不一样的,(如何保证最终一致的?) 2.nameServer维护的boker信息 发生变化时,不会像z ...
- 5、pgpool-II高可用性(一)数据库的高可用性
官网示例 一.实现原理 使用 pgpool-II 软件:我们常用来实现流复制的高可用性:备库只读的,不可写:就是当主库出现问题时:需要把备库自动激活为主库:来接管服务. 这在其他高可用软件也有这功能, ...
- unittest框架中读取有特殊符号的配置文件内容的方法-configparser的RawConfigParser类应用
在搭建Unittest框架中,出现了一个问题,配置文件.ini中,出现了特殊字符如何处理? 通过 1.configparser的第三方库对应的ConfigParser类,无法完成对特殊字符的读取: # ...
- 【MMT】ICLR 2020: MMT(Mutual Mean-Teaching)方法,无监督域适应在Person Re-ID上性能再创新高
原文链接 小样本学习与智能前沿 . 在这个公众号后台回复"200708",即可获得课件电子资源. 为了减轻噪音伪标签的影响,文章提出了一种无监督的MMT(Mutual Mean-T ...
- MySQL 连接为什么挂死了
声明:本文为博主原创文章,由于已授权部分平台发表该文章(知乎.云社区),可能造成发布时间方面的困扰. 一.背景 近期由测试反馈的问题有点多,其中关于系统可靠性测试提出的问题令人感到头疼,一来这类问题有 ...
- git全流程
服务器:Ubuntu 使用git前准备工作: 下载git之前先更新: apt-get update 安装git: apt-get install git 创建本地仓库: mkdir test git初 ...