设为首页 收藏本站
查看: 652|回复: 0

[经验分享] redis 事件驱动机制

[复制链接]

尚未签到

发表于 2016-12-19 11:33:44 | 显示全部楼层 |阅读模式
  redis基于事件驱动构建服务,有两种事件类型,文件事件FileEvent,和时间事件TimeEvent

1,文件事件
  以多路IO复用程序来同事监听多个套接字,处理网络连接的应答,读取,写入和关闭操作,并根据执行任务的不同分配不同的事件处理器来处理。

    a, 结构体

/* File event structure */
/* 文件事件结构体 */
typedef struct aeFileEvent {
//只为读事件或者写事件中的1种
int mask; /* one of AE_(READABLE|WRITABLE) */
//读事件方法, 根据不同任务关联不同的处理器,如应答、请求..
aeFileProc *rfileProc;
//写事件方法,根据不同任务关联不同的处理器,如写入..
aeFileProc *wfileProc;
//客户端数据,指向 redisClient 的指针
void *clientData;
} aeFileEvent;
     b, 处理文件事件的流程图
DSC0000.jpg

  IO多路复用函数监听多个套接字,当套接字上注册的套接字注册的事件类型触发时,会将其放入队列中,顺序进行处理。处理时根据套接字上的事件类型调用关联的事件处理器。这里注意,如果一个套接字即可读又可写,则先处理读再处理写。

    c, 文件事件的几种事件处理器
  连接应答处理器,是与监听服务套接字的读事件进行关联的,当有新的客户端发起连接时(connect),连接应答处理器会accept并返回客户端套接字,创建客户端状态,添加到redis client链表,该结构维护了客户端的各种信息(具体之后讲)。并将读事件与客户端套接字进行关联。
  命令请求处理器,是与客户端套接字的读事件进行关联,读取客户端发送来的命令并放入clientdata中的输入缓冲区,在进行协议解析并调用对应的命令处理..。.
  命令回复处理器,是与客户端套接字的写事件进行关联,当命令请求后需要向客户端发送数据时,注册该事件,当客户端返回可以写入时,则事件触发,将数据写入。这里需要注意,因为redis是单线程的,因此当数据量超过一个阀值时,会重新注册并返回,避免阻塞过长时间,下次触发再发送。

2,时间事件
  记录在指定时间点运行的事件,多个时间事件以无序链表的形式保存在服务器状态中。

    a, 结构体

/* Time event structure */
/* 时间事件结构体 */
typedef struct aeTimeEvent {
//时间事件id,累加增加,id降序链表
long long id; /* time event identifier. */
//时间秒数
long when_sec; /* seconds */
//时间毫秒
long when_ms; /* milliseconds */
//时间事件中的处理函数
aeTimeProc *timeProc;
//被删除的时候将会调用的方法
aeEventFinalizerProc *finalizerProc;
//客户端数据
void *clientData;
//时间结构体内的下一个结构体
struct aeTimeEvent *next;
} aeTimeEvent;
     b, 定时事件和周期性事件
  执行一次和重复执行的区别,定时需要在处理完后删除事件。周期需要更新when时间。根据事件处理器的返回值区分是那个时间事件。
  c, 使用无序链表实现,每次需要遍历所有链表,效率低。但现在redis正常只有一个serverCron...benchmark下有两个。实现没含量,最小堆实现都比这个好,事件多了会死循环,切效率低,这里不多讲了。

3,事件的循环调度

    a, 结构体

typedef struct aeFiredEvent {  
//文件描述符 fd  
int fd;  
// 触发的事件 读写
int mask;  
} aeFiredEvent;// 已触发的事件

// 事件循环结构体
/* State of an event based program */
typedef struct aeEventLoop {
int maxfd;   /* highest file descriptor currently registered */
int setsize; /* max number of file descriptors tracked */
// 记录最大的定时事件 id + 1
long long timeEventNextId;
// 用于系统时间的矫正
time_t lastTime;     /* Used to detect system clock skew */
// I/O 文件事件表
aeFileEvent *events; /* Registered events */
// 被触发的事件表
aeFiredEvent *fired; /* Fired events */
// 定时事件表
aeTimeEvent *timeEventHead;
// 事件循环结束标识
int stop;
// 对于不同的 I/O 多路复用技术,有不同的数据,详见各自实现
void *apidata; /* This is used for polling API specific data */
// 新的循环前需要执行的操作
aeBeforeSleepProc *beforesleep;
} aeEventLoop;
  结构体之间的关系如下图
DSC0001.png


    b, 事件循环
  基本就是用一个无限循环,然后再循环中去检测各个事件的发生。若服务器未关闭则一直循环,且先处理文件事件,再处理时间事件。首先计算定时时间的最快触发时间,这样保证了阻塞时间不会影响时间事件的处理,同时避免频繁地轮询时间事件。然后是阻塞时间等待文件IO事件的触发,如果等待时间内内有文件事件,阻塞时间超时返回,时间事件正好触发。若阻塞时间内触发文件IO事件,则直接返回处理,这是时间事件还未触发,则进入新的循环,重新计算时间事件的时间,这样再处理文件事件的同时,逐步逼近时间事件。流程图如下:
DSC0002.jpg

  注意时间事件不是准时的,只能保证在定时的时间之后处理而不是按时处理。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-316424-1-1.html 上篇帖子: 3.通过Jedis访问Redis——八种调用方式 下篇帖子: redis学习笔记之String
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表