redis事件机制

在这里插入图片描述
redis服务器是一个由事件驱动(死循环)的程序,它总共就干两件事:

  1. 文件事件:利用I/O复用机制,监听Socket等文件描述符发生的事件,如网络请求
  2. 时间事件:定时触发的事件,负责完成redis内部定时任务,如生成RDB文件、清除过期事件

redis事件api

  1. aeApiCreate:初始化I/O复用机制上下文环境

  2. aeApiAddEvent、aeApiDelEvent:增加或删除一个监听对象

  3. aeApiPoll:阻塞进程,等待事件就绪或给定事件到期

  4. aeEventLoop:redis事件循环器,负责管理事件

  5. aeFileEvent:存储一个文件描述符已注册的文件事件

  6. aeTimeEvent:存储一个时间事件的信息

  7. redis启动时创建的事件

    1. 初始化aeEventLoop属性
    2. aeApiCreate由I/O复用层实现,并初始化具体的I/O复用机制执行的上下文环境
  8. 监听TCP Socket,并指定函数处理

    1. 如果超出eventLoop.setsize限制,则返回错误
    2. aeApiAddEvent函数由I/O复用层实现,调用I/O复用函数添加监听事件对象
    3. 初始化aeFileEvent属性
  9. redis定时任务

    1. 初始化aeTimeEvent属性,计算下一次时间事件执行事件
    2. 头插到eventLoop.timeEventHead链表
  10. 事件循环器的运行

    1. 阻塞进程,等待文件事件就绪或时间事件到达执行事件
    2. 按规则计算进程最大阻塞时间
      1. 查找最先执行的时间事件,若有,则用该时间减去当前时间
      2. 检查是否AE_DONT_WAIT标志,若无则一直阻塞,若有,则不阻塞,轮询系统是否有就绪事件
    3. 进程阻塞前,执行beforeSleep函数
    4. aeApiPoll负责阻塞进程,直到有文件事件就绪或时间到期
    5. 进程阻塞后,执行afterSleep函数
    6. aeApiPoll返回已就绪的文件事件数量并处理
    7. 通常redis会优先处理read事件再处理write事件,以方便服务器尽快处理请求返回结果给客户端。aeApiAddEvent如果设置了优先处理write属性,则会优先处理write事件。
    8. 处理时间事件
  11. 处理时间事件

    1. 判断上一次执行事件的时间是否比当前时间大?若是就说明系统时间有问题,则将所有时间事件过期时间置为0提前执行,提前执行危害小于延后执行.
    2. 遍历时间事件
    3. 若事件已删除,则将其从链表中删除
    4. 若时间事件已经到了执行时间,则删除
    5. 处理下一个时间事件
  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是Redis事件机制的C代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/time.h> #include <unistd.h> #include <fcntl.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/epoll.h> #define MAX_EVENTS 64 int main(int argc, char *argv[]) { int listen_fd, conn_fd, epoll_fd, nfds, n, i; struct sockaddr_in serv_addr, cli_addr; socklen_t cli_len = sizeof(cli_addr); struct epoll_event ev, events[MAX_EVENTS]; // 创建监听套接字 listen_fd = socket(AF_INET, SOCK_STREAM, 0); if (listen_fd < 0) { perror("socket error"); exit(1); } // 设置套接字为非阻塞模式 if (fcntl(listen_fd, F_SETFL, fcntl(listen_fd, F_GETFL, 0) | O_NONBLOCK) < 0) { perror("fcntl error"); exit(1); } // 绑定地址和端口 memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(8080); if (bind(listen_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { perror("bind error"); exit(1); } // 监听套接字 if (listen(listen_fd, SOMAXCONN) < 0) { perror("listen error"); exit(1); } // 创建epoll实例 epoll_fd = epoll_create1(0); if (epoll_fd < 0) { perror("epoll_create1 error"); exit(1); } // 添加监听套接字到epoll实例中 ev.events = EPOLLIN; ev.data.fd = listen_fd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &ev) < 0) { perror("epoll_ctl error"); exit(1); } // 进入事件循环 while (1) { nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); if (nfds < 0) { perror("epoll_wait error"); exit(1); } for (i = 0; i < nfds; i++) { if (events[i].data.fd == listen_fd) { // 有新的连接请求 conn_fd = accept(listen_fd, (struct sockaddr *)&cli_addr, &cli_len); if (conn_fd < 0) { perror("accept error"); continue; } // 将新的连接套接字添加到epoll实例中 ev.events = EPOLLIN | EPOLLET; ev.data.fd = conn_fd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_fd, &ev) < 0) { perror("epoll_ctl error"); exit(1); } } else { // 有数据可读 char buf[1024]; n = read(events[i].data.fd, buf, sizeof(buf)); if (n < 0) { perror("read error"); continue; } else if (n == 0) { // 连接已关闭 if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL) < 0) { perror("epoll_ctl error"); exit(1); } close(events[i].data.fd); } else { // 将数据回写给客户端 write(events[i].data.fd, buf, n); } } } } return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值