一文聊聊Redis中的epoll和文件事件

本篇文章给大家介绍一下redis中的文件事件,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

一文聊聊Redis中的epoll和文件事件

事件驱动

Redis 服务器是事件驱动程序,分为文件事件和时间事件

文件事件:socket 的可读可写事件定时任务

【相关推荐:Redis视频教程】

它们都被封装到aeEventLoop结构体中

typedef struct aeEventLoop {int stop; // 标识事件是否结束aeFileEvent *events; // 文件事件数组,存储已注册的文件事件aeFireEvent *fired; // 存储被触发的文件事件aeTimeEvent *timteEventHead; // 多个时间事件形成的链表void *apidata; // I/O模型的封装aeBeforeSleepProc *beforesleep; // 进程阻塞前执行aeBeforeSleepProc *aftersleep; // 进程被唤醒后执行} aeEventLoop;

登录后复制

事件驱动程序实际上也是通过while/for循环,循环等待事件的发生

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

登录后复制

aeProcessEvents为事件处理主函数

epoll

Redis 客户端通过 TCP socket 与服务端交互,文件事件指的就是 socket 的可读可写事件。一般使用非阻塞模式,相关的 I/O 多路复用有select/epoll/kqueue等,不同的操作系统不同的实现。

以epoll为例,它是 Linux 内核为处理大量并发网络连接而提出解决方案。epoll提供3个 API

epoll_create 创建一个 epoll 专用的文件描述符,用于后续 epoll 相关 API 调用

int epoll_create(int size)// size 告知内核程序期望注册的网络连接数目,Linux 2.6.8后改为内核动态分配// 返回参数是 epoll 专用的文件描述符

登录后复制

epoll_ctl 函数向 epoll 注册、修改或删除需要监控的事件

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)// epfd 函数 epoll_create 返回的 epoll 文件描述符// op 操作类型 EPOLL_CTL_ADD:注册事件; EPOLL_CTL_MOD:修改网络连接事件; EPOLL_CTL_DEL:删除事件// fd 网络连接的 socket 文件描述符// event 需要监控的事件

登录后复制

epoll_wait 函数会会阻塞进程,直到监控的若干网络连接有事件发生

int epoll_wait(int epfd, struct epoll_event *event, int maxevents, int timeout)// epfd 函数epoll_create返回的epoll文件描述符// epoll_event 作为输出参数使用,用于回传已触发的事件数组// maxevents 每次能处理的最大事件数目// timeout epoll_wait 函数阻塞超时时间,如果超过 timeout 时间还没有事件发生,函数就不再阻塞直接返回;当 timeout 等于0是函数立即返回,timeout 等于-1时函数一直阻塞到有事件发生

登录后复制

文件事件

Reids 没有直接使用 epoll 的 API,而是同时支持4种I/O多路复用模型,对这些模型的 API 进行了封装。然后在编译阶段检查操作系统支持的I/O多路复用模型,并按照策略来决定复用那张模型。

还是以 epoll 为例,Redis 进行了如下封装

// 对应 epoll_createstatic int aeApiCreate(aeEventLoop *eventLoop)// 对应 epoll_ctl 添加事件static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask)// 对应 epoll_ctl 删除事件static int aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask)// 对应 epoll_waitstatic int aeApiPool(aeEventLoop *eventLoop, struct timeval *tvp)

登录后复制

回忆一下上面提到的eventLoop结构体,其成员 apidata 指向4种I/O多路复用模型对象;events 存储需要监控的事件数组,以 socket 文件描述符作为数组索引存取元素;fired 存储已触发的事件数组。

文件事件的结构体定义如下:

typedef struct aeFileEvent {int mask; // 文件事件类型 AE_READABLE 可读事件;AE_WRITEABLE 可写事件aeFileProc *rfileProc; // 读事件处理函数指针aeFileProc *wfileProc; // 写事件处理函数指针void *clientData; // 指向对应的客户端对象} aeFileEvent;

登录后复制

看一下创建文件事件 aeCreateFileEvent 的实现

int aeCreateFileEvent (aeEventLoop *eventLoop, int fd, int mask, aeFileProc *proc, void *clientData) {aeFileEvent *fe = &eventLoop->evnts[fd];if (aeApiAddEvent(eventLoop, fd, mask) == -1)return AE_ERR;fe->mask |= mask;if (mask & AE_READABLE) fe->rfileProc = proc;if (mask & AE_WRITABLE) fe->wfileProc = proc;fe->clientData = clientData;return AE_OK;}

登录后复制

Redis 服务器会通过创建各类文件事件来处理事务,比如:

启动时创建 socket 并监听,等待客户端连接

aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE, acceptTcpHandler, NULL);

登录后复制客户端与服务器建立 socket 连接之后,服务器会等待客户端的命令请求

aeCreateFileEvent(server.el, fd, AE_READABLLE, readQueryFromClient, c);

登录后复制服务器处理完客户端的命令请求之后,命令回复会暂时缓存在client结构体的buf缓冲区,待客户端文件描述符的可写事件发生时,才会真正往客户端发送命令回复

aeCreateFileEvent(server.el, c->fd, AE_READABLLE, sendReplyToClient, c);

登录后复制

Redis 所有事件的执行都是通过aeProcessEvents函数来控制。在其中,执行文件事件会出现阻塞情况(epoll_wait),如果阻塞事件太长了,会妨碍到时间事件(定时)的执行,为避免出现这种情况,在实现文件事件时传入的等待时间,是计算最早发生的时间事件得到的

int aeProcessEvents(aeEventLoop *eventLoop, int flags) {shortest = aeSearchNearestTimer(eventLoop);long long ms = (shortest->when_sec - now_sec) * 1000 + shortest->when_ms - now_ms;// 阻塞事件发生numevents = aeApiPoll(eventLoop, ms);for (j=0; j events[eventLoop->fired[j]].fd];// 处理文件事件,即根据类型执行rfileProc或wfileProc}// 处理时间事件processed += processTimeEvents(eventLoop);}

登录后复制

总结

现在我们来整体看一下 Redis 服务器相应命令的流程

1.png

aeMain 函数通过调用 aeProcessEvents 函数来进行文件事件和时间事件的调度和执行。aeEventLoop 中记录了事件相关的信息。首先通过 aeSearchNearestTimer 函数获取最短的时间事件的执行时间间隔n,然后调用 aeApiPoll 函数获取监听到的套接字,最后执行与套接字向对应的事件处理函数 rfileProc 和 wfileProc,最后再执行时间事件函数 processTimeEvents。

一次完整的客户端与服务端连接事件:

器监听套件字的 AE_READABLE 事件,当客户端发送连接请求产生 AE_READABLE  事件,服务端会对客户端的连接请求进行应答,将客户端套接字的 AE_READABLE 事件与命令请求处理函数(aeFileProc),客户端可以向服务端发送命令请求了

端向服务端发送一个命令请求,客户端套接字将产生 AE_READABLE 事件,引发命令处理器去执行,执行命令将产生相应的命令回复,服务端将客户端套接字的 AE_WRITABLE 事件与命令回复处理函数(aeFileProc)关联

端尝试读取命令回复时,客户端套接字将产生 AE_WRITABLE 事件,触发命令回复处理器执行,当命令回复处理器将命令回复全部写入套接字之后,服务器就会接触客户端套接字的 AE_WRITABLE 事件与命令回复处理函数(aeFileProc)之间的关联

更多编程相关知识,请访问:编程视频!!

以上就是一文聊聊Redis中的epoll和文件事件的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2039892.html

(0)
上一篇 2025年2月24日 00:06:32
下一篇 2025年2月18日 07:28:20

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • 总结分享几款实用Redis可视化工具

    本篇文章总结了几款实用redis可视化工具分享给大家,希望对大家有所帮助,快来收藏吧! 不啰嗦,我们直接开始! 1、命令行 1.1、iredis 利用iredis,用|将redis通过pipe用shell的其他工具,比如jq/fx/rg/s…

    2025年2月24日 数据库
    200
  • 浅谈Redis中的字典、哈希算法和ReHash原理

    本篇文章带大家了解一下redis中的字典、哈希算法和rehash原理,希望对大家有所帮助! Redis 中的字典被广泛用于实现Redis的各种功能,其中包括数据库和哈希键。 字典的底层实现为哈希表,每个字典带有两个哈希表,一个平时使用,另一…

    2025年2月24日
    200
  • 浅析Redis缓存中的8种淘汰策略

    本篇文章带大家来聊聊redis缓存中的8种淘汰策略,看看应该怎么使用它们,希望对大家有所帮助! 我们知道Redis缓存使用内存来保存数据,但内存大小毕竟有限,随着要缓存的数据量越来越大,有限的缓存空间不可避免地会被写满。这时候就需要缓存的淘…

    2025年2月24日
    200
  • Redis怎么进行去重?4种去重方法浅析

    redis怎么进行去重?下面本篇文章给大家介绍一下redis去重的4种方法,希望对大家有所帮助! 这篇文章主要介绍了Redis实现唯一计数的3种方法分享,本文讲解了基于SET、基于 bit、基于 HyperLogLog三种方法,需要的朋友可…

    2025年2月24日
    200
  • 浅析Redis中AOF的原理和缺点

    本篇文章带大家了解一下redis持久化中的aof,介绍一下aof原理、aof缺点,希望对大家有所帮助! AOF 上文我们提到了rRedis中的一种持久化方式就是RDB 此文我们来讲另一种实现方式那就是AOF AOF是通过只记录Redis写入…

    2025年2月24日
    200
  • redis中分布式session不一致性怎么办

    分布式session不一致性怎么办?下面本篇文章给大家介绍一下redis中分布式session不一致性的解决方案,希望对大家有所帮助! 分布式session不一致性解决方案 一、Session有什么作用? Session 是客户端与服务器通…

    2025年2月24日 数据库
    200
  • Redis中什么是慢查询、订阅模式

    本篇文章给大家介绍一下redis中的慢查询和订阅模式,希望对大家有所帮助! 慢查询 慢查询日志就是系统在命令执行时每条命令的执行时间,当超过阀值,就将这条命令记录下来。【相关推荐:Redis视频教程】 Redis命令执行流程 发送命令 命令…

    2025年2月24日 数据库
    200
  • 深入了解Redis中的主从同步机制

    本篇文章带大家了解一下redis中的主从同步,介绍一下redis主从的两种结构模型、主从关系的建立、主从复制策略等,希望对大家有所帮助! 之前的文章中详细分析了redis的特性和核心原理,从本篇开始将对redis的部署结构和运行模式进行分析…

    2025年2月24日 数据库
    200
  • 浅析Python中怎么用Redis

    python中怎么用redis?下面本篇文章给大家介绍一下python使用redis的方法,希望对大家有所帮助! 前面我们都是使用 Redis 客户端对 Redis 进行使用的,但是实际工作中,我们大多数情况下都是通过代码来使用 Redis…

    2025年2月24日 数据库
    200
  • 深入聊聊Redis中的5种基本数据类型

    本篇文章带大家详细了解一下redis中的5种基本数据类型(string字符串、list列表、set集合、hash散列、zset有序集合),希望对大家有所帮助! Redis数据结构简介 对redis来说,所有的key(键)都是字符串。我们在谈…

    2025年2月24日
    200

发表回复

登录后才能评论