自顶向下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创建一个. 下载链 ...
随机推荐
- LeetCode 中等题解(3)
34 在排序数组中查找元素的第一个和最后一个位置 Question 给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 你的算法时间复杂 ...
- MySQL获取webshell的几种方式
select ... into outfile 需要满足的条件 对web目录有写权限 GPC关闭(GPC:是否对单引号转义) 有绝对路径(读文件可以不用,写文件需要) 没有配置secure-file- ...
- mysql case when语句的使用
case具有两种格式.简单case函数和case搜索函数. 简单函数 CASE [col_name] WHEN [value1] THEN [result1]-ELSE [default] END 搜 ...
- Acwing 245.你能回答这些问题吗
题目描述 给定长度为N的数列A,以及M条指令,每条指令可能是以下两种之一: 1."1 x y",查询区间 [x,y] 中的最大连续子段和,即 maxx≤l≤r≤y{∑ri=lA[i ...
- 知识点:C语言进阶提高篇,自定义数据类型:枚举
一.枚举的概念 枚举是C语言中的一种基本数据类型,并不是构造类型,它可以用于声明一组常数.当一个变量有几个固定的可能取值时,可以将这个变量定义为枚举类型.比如,你可以用一个枚举类型的变量来表示季节,因 ...
- 卡耐基梅隆大学(CMU)元学习和元强化学习课程 | Elements of Meta-Learning
Goals for the lecture: Introduction & overview of the key methods and developments. [Good starti ...
- 饱含辛酸开发 WPF CustomControl
引言 不知不觉间WPF开发已有两年光景,或许有很多人会问WPF还需要学习吗?WPF还有前途吗?其实我也很担心这个问题. .Net Core3.x已经支持WPF开发,.Net 5也宣布要支持WPF.是否 ...
- java并发编程实战《四》互斥锁(下)
互斥锁(下):如何用一把锁保护多个资源? 一把锁可以保护多个资源,但是不能用多把锁来保护一个资源. 那如何保护多个资源? 当我们要保护多个资源时,首先要区分这些资源是否存在关联关系. 如下代码 ...
- 通过Dbeaver创建表格的时候,设置主键
通过Dbeaver创建表格的时候,设置主键 Dbeaver介绍: 这是一个开源的数据库连接工具,你需要安装jre才可以使用这个软件 在使用Dbeaver创建表的时候,会发现,不能直观地设置主键 这 ...
- Python中定义文档字符串__doc__需要注意格式对齐的处理
Python中的文档字符串是个很不错的提升代码交付质量.编写文档方便的特征,但是需要注意在使用文档字符串时,将文档字符串标识的引号对必须遵守缩进的规则,否则Python语法检查时会无法通过,而引号内的 ...