Redis 的事件分类

分类 描述
定时器 线程内定时响应,更新缓存时间、关闭非活动的客户端连接等等
pipe 线程间通信,用于其他线程通知主线程退出aeApiPoll()
unixsocket 本地进程间通信,当client和redis部署在一台机器上时,使用unixsocket性能会更高
TCP 网络或进程间通信

Redis支持4种I/O模型:evport、epoll、kqueue、select,通过宏定义决定使用某一个

事件处理 描述 接口函数名称 模型实现
select kqueue epoll evport
aeCreateEventLoop() 创建I/O模型句柄 aeApiCreate()   kqueue() epoll_create() port_create()
aeCreateFileEvent() 注册事件并指定回调函数 aeApiAddEvent() FD_SET() kevent() epoll_ctl() port_associate()
aeDeleteFileEvent() 删除事件 aeApiDelEvent() FD_CLR() kevent() epoll_ctl() port_dissociate()
aeProcessEvents() 事件循环 aeApiPoll() select() kevent() epoll_wait() port_getn()

1 配置加载

config.c : void loadServerConfig(char *filename, char *options)

加载配置文件端口

else if (!strcasecmp(argv[],"port") && argc == ) {
server.port = atoi(argv[]);
if (server.port < || server.port > ) {
err = "Invalid port"; goto loaderr;
}

加载配置文件绑定的网卡地址

else if (!strcasecmp(argv[],"bind") && argc >= ) {
int j, addresses = argc-; if (addresses > CONFIG_BINDADDR_MAX) {
err = "Too many bind addresses specified"; goto loaderr;
}
for (j = ; j < addresses; j++)
server.bindaddr[j] = zstrdup(argv[j+]);
server.bindaddr_count = addresses;
}

加载配置文件最大连接数量

else if (!strcasecmp(argv[],"maxclients") && argc == ) {
server.maxclients = atoi(argv[]);
if (server.maxclients < ) {
err = "Invalid max clients limit"; goto loaderr;
}
}

2 创建I/O模型句柄

server.c : void initServer(void)

server.el = aeCreateEventLoop(server.maxclients+CONFIG_FDSET_INCR);
if (server.el == NULL) {
serverLog(LL_WARNING,
"Failed creating the event loop. Error message: '%s'",
strerror(errno));
exit();
}

3 监听连接

根据配置文件port、bind字段设置的内容监听IPv4、IPv6的地址,若未指定,则监听IP:0.0.0.0

server.c : void initServer(void)

if (server.port !=  &&
listenToPort(server.port,server.ipfd,&server.ipfd_count) == C_ERR)
exit() if (server.unixsocket != NULL) {
unlink(server.unixsocket); /* don't care if this fails */
server.sofd = anetUnixServer(server.neterr,server.unixsocket,
server.unixsocketperm, server.tcp_backlog);
if (server.sofd == ANET_ERR) {
serverLog(LL_WARNING, "Opening Unix socket: %s", server.neterr);
exit();
}
anetNonBlock(NULL,server.sofd);
}

listenToPort()返回创建的I/O句柄和数量。

unixsocket 是用于本地进程间通信的

4 注册事件

server.c : void initServer(void)

4. 1 注册定时器事件

指定回调函数 serverCron() ,该函数用于处理时间类逻辑,比如将长时间无数据到来的客户端连接关闭。

if (aeCreateTimeEvent(server.el, , serverCron, NULL, NULL) == AE_ERR) {
serverPanic("Can't create event loop timers.");
exit();
}

4.2 注册I/O型事件

注册TCP 连接、unixsockt 连接、pipe 读等事件。前两者是在有新连接到来时响应,用来接受连接并通过aeCreateFileEvent()注册数据读写事件;后者pipe的读事件用于其他线程通知本线程退出aeApiPoll(),所以其回调函数可以什么都不做,只是个空函数。

for (j = ; j < server.ipfd_count; j++) {
if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE,
acceptTcpHandler,NULL) == AE_ERR)
{
serverPanic(
"Unrecoverable error creating server.ipfd file event.");
}
} if (server.sofd > && aeCreateFileEvent(server.el,server.sofd,AE_READABLE,
acceptUnixHandler,NULL) == AE_ERR) serverPanic("Unrecoverable error creating server.sofd file event."); if (aeCreateFileEvent(server.el, server.module_blocked_pipe[], AE_READABLE,
moduleBlockedClientPipeReadable,NULL) == AE_ERR) {
serverPanic(
"Error registering the readable event for the module "
"blocked clients subsystem.");
}

5 事件循环及处理

ae.c

启动事件循环,就是个while死循环,循环调用事件处理函数:aeProcessEvents()

void aeMain(aeEventLoop *eventLoop) {
eventLoop->stop = ;
while (!eventLoop->stop) {
if (eventLoop->beforesleep != NULL)
eventLoop->beforesleep(eventLoop);
aeProcessEvents(eventLoop, AE_ALL_EVENTS|AE_CALL_AFTER_SLEEP);
}
}

事件处理主要干的几件事

  1. 查找距离最近的要响应的定时器,计算相隔时间
  2. aeApiPoll 检测 I/O 事件,设定超时时间为第1步计算得到的时间
  3. 对于有事件到来的 I/O,调用注册时指定的回调函数
  4. 对于第1步找到定时器,调用注册时指定的回调函数
int aeProcessEvents(aeEventLoop *eventLoop, int flags)
{
int processed = , numevents; if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return ; if (eventLoop->maxfd != - ||
((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) {
int j;
aeTimeEvent *shortest = NULL;
struct timeval tv, *tvp; if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT))
shortest = aeSearchNearestTimer(eventLoop);
if (shortest) {
//...
} else {
//...
} numevents = aeApiPoll(eventLoop, tvp); if (eventLoop->aftersleep != NULL && flags & AE_CALL_AFTER_SLEEP)
eventLoop->aftersleep(eventLoop); for (j = ; j < numevents; j++) {
//...
}
} if (flags & AE_TIME_EVENTS)
processed += processTimeEvents(eventLoop); return processed;
}

Redis源码 - 事件管理的更多相关文章

  1. Redis源码阅读(一)事件机制

    Redis源码阅读(一)事件机制 Redis作为一款NoSQL非关系内存数据库,具有很高的读写性能,且原生支持的数据类型丰富,被广泛的作为缓存.分布式数据库.消息队列等应用.此外Redis还有许多高可 ...

  2. Redis 源码简洁剖析 10 - aeEventLoop 及事件

    aeEventLoop IO 事件处理 IO 事件创建 读事件处理 写事件处理 时间事件处理 时间事件定义 时间事件创建 时间事件回调函数 时间事件的触发处理 参考链接 Redis 源码简洁剖析系列 ...

  3. Redis源码分析:serverCron - redis源码笔记

    [redis源码分析]http://blog.csdn.net/column/details/redis-source.html   Redis源代码重要目录 dict.c:也是很重要的两个文件,主要 ...

  4. Redis 源码简洁剖析 07 - main 函数启动

    前言 问题 阶段 1:基本初始化 阶段 2:检查哨兵模式,执行 RDB 或 AOF 检测 阶段 3:运行参数解析 阶段 4:初始化 server 资源管理 初始化数据库 创建事件驱动框架 阶段 5:执 ...

  5. Redis源码漂流记(二)-搭建Redis调试环境

    Redis源码漂流记(二)-搭建Redis调试环境 一.目标 搭建Redis调试环境 简要理解Redis命令运转流程 二.前提 1.有一些c知识简单基础(变量命名.常用数据类型.指针等) 可以参考这篇 ...

  6. 一起学习redis源码

    redis的一些介绍,麻烦阅读前面的几篇文章,想对redis的详细实现有所了解,强力推荐<redis设计与实现>(不仅仅从作者那儿学习到redis的实现,还有项目的管理.思想等,作者可能比 ...

  7. redis源码笔记(一) —— 从redis的启动到command的分发

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载联系作者并保留声明头部与原文链接https://luzeshu.com/blog/redis1 本博客同步在http://www.cnblog ...

  8. Redis源码学习:字符串

    Redis源码学习:字符串 1.初识SDS 1.1 SDS定义 Redis定义了一个叫做sdshdr(SDS or simple dynamic string)的数据结构.SDS不仅用于 保存字符串, ...

  9. Redis源码剖析和注释(七)--- 快速列表(quicklist)

    Redis 快速列表(quicklist)1. 介绍quicklist结构是在redis 3.2版本中新加的数据结构,用在列表的底层实现. 通过列表键查看一下:redis 列表键命令详解 127.0. ...

随机推荐

  1. Python第十四天 序列化 pickle模块 cPickle模块 JSON模块 API的两种格式

    Python第十四天 序列化  pickle模块  cPickle模块  JSON模块  API的两种格式 目录 Pycharm使用技巧(转载) Python第一天  安装  shell  文件 Py ...

  2. Parameter 'ids' not found. Available parameters are [array]

    传的参数是一个数组, Long[] ids 后台错误写法 <delete id="deleteById"> delete from table where id in ...

  3. 【spring源码分析】IOC容器初始化(四)

    前言:在[spring源码分析]IOC容器初始化(三)中已经分析了BeanDefinition注册之前的一些准备工作,下面将进入BeanDefinition注册的核心流程. //DefaultBean ...

  4. Codeforces #541 (Div2) - F. Asya And Kittens(并查集+链表)

    Problem   Codeforces #541 (Div2) - F. Asya And Kittens Time Limit: 2000 mSec Problem Description Inp ...

  5. 你不需要 jQuery,但你需要一个 DOM 库

    写这篇文章的目的,一方面是介绍一下自己编写的模块化 DOM 库 domq.js,另一方面是希望大家对 jQuery 有一个正确的认识,即使 jQuery 已经逐渐退出历史舞台,但是它的 API 将会以 ...

  6. FB商务管理平台(Business Manager) (2)

    Business Manager 商务管理平台(以下简称BM)API 一站式管理广告帐户.主页及相关的工作人员. BM功能结构(其中:账户下的节点属于市场营销API) API / SDK FB提供了多 ...

  7. Vue 环境搭建(win10)

    1.安装node node官网安装地址 推荐安装稳定版本(LTS)以及安装路径为系统盘(C) 查看node安装成功否 注释:以下命令使用 命令提示符(管理员)权限,win10 对user权限的限制了访 ...

  8. MySQL之开发规范

    一..数据库命名规范 1.所有数据库对象名称必须使用小写字母并用下划线分割 2.所有数据库对象名称禁止使用mysql保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来) 3.数据库对象的命 ...

  9. NodeJs之定时器与队列

    NodeJs之定时器与队列 一,介绍与需求 1.1,介绍 定时任务(node-schedule),是针对Node.js的一种灵活的cron-like和not-cron-like作业调度程序.它允许您使 ...

  10. 什么是CAS机制?(转)

    围绕下面四个点展开叙述: 一:什么是CAS机制? 二:Java当中CAS的底层实现 三:CAS的ABA问题和解决方法 四:java8对CAS的优化 一:什么是CAS机制? 我们先看一段代码: 启动两个 ...