Redis Source Code Read Log( 3. aeEventLoop Arch EPOLL LT mode arch)

Part 1: Basic Structure

aeTimeEvent

双链表结构

aeFileEvent & aeFiredEvent

aeApiState

aeEventLoop

Part 2: eventLoop Arch

aeMain

main data flow:

1. Redis Sever 启动之后,监听 socket ,开始 accept 客户端的连接
2. 客户端连接上来之后,注册 client fd ae 中,并注册读事件 callback
3. Ae 触发读事件之后,读取客户端数据
4. 解析数据,获取 Redis 的不同命令
5. 调用不同命令注册的 callback 函数,进行不同的处理

Note:

    1. Socket fd均为nonblock模式,采用epoll进行LT模式触发,epoll_wait 返回

    2. 客户端reply data,在read data处理之后,进行reply data的缓存

    3. Reply databeforeSleep中进行data send,继续进入 epoll_wait 的阻塞等待

acceptTCPHandler

handleMessage

Linux platform 上,Redis 采用 non-block socket + epoll LT + 异步回射 + 个别场景下 引入 poll with timeout的阻塞同步 的模型。另外,Redis中对epoll 触发出来的状态进行了记录以及转移。全部存储在Redis自身的 aeEventLoop结构中。通过 aeCreateTimeEvent 以及 aeCreateFileEvent 进行两种事件,timer事件以及 File事件的注册。

1. timer:  Redis采用 epoll_wait 超时机制,实现了定时的返回触发。

示例如下:

#include <stdio.h>
#include <stdlib.h>

#include <unistd.h>
#include <sys/epoll.h>

void cron_task(int cnthz)
{
    if (cnthz % 3 == 0)
    {
        printf("handle task every 3 hz\n");
    }
    if (cnthz % 5 == 0)
    {
        printf("handle task every 5 hz\n");
    }
    if (cnthz % 8 == 0)
    {
        printf("handle task every 8 hz\n");
    }
}

int main()
{
    int hz = 500; // every 500 millisec, 0.5 sec.
    int epfd = epoll_create(1024);
    struct epoll_event events[10];
    int cnthz = 0;
    while (1)
    {
        epoll_wait(epfd, events, 10, hz);
        cron_task(cnthz);
        cnthz++;
        // for auto exit.
        if (cnthz == 20)
        {
            break;
        }
    }
    close(epfd);
    return 0;
}

这是个自实现的简单时钟。每隔500 毫秒震荡一次。Redis中称之为 hz,表示最小的时钟颗粒度。以上的代码用的是最简单的方式,就是记录震荡次数,然后,根据次数,去取模计时。这种方式,跟splee 500 毫秒,看似效果一致。但是,epoll_wait是可以同时监听fd事件的。就不会timeout返回。Redis中是通过get system time相关的接口去计时比较。对比两个时间戳直接的距离,计算时间流逝。

需要注意的是,redis的timer task被记录在EventLoop结构中,内中实现是一个双链表。每次都是需要去检索都是O(n)的复杂度。每次调用cron task的时候,都要去遍历,比较,更新时间戳等操作。所以,timer任务是不会太多的。

2. file event.

由于进程中能够打开的fd 是有限的。比如默认大多数都是1024。服务端程序可能改成 65535,或者更大。可采用ulimit -n 命令进行查看。0, 1, 2 作为系统的默认设备。redis日志回占用1个。然后 redis至少会启用一个fd, socket去accept client connection 然后 pipe 等等。所以Redis内部会保持一些自用,CONFIG_MIN_RESERVED_FDS 宏为 32 个,为自留用fd数量,基于安全层面,扩展层面的考虑,在此基础上,又增加了 96.保证保持在128以内。接下来的fd主要是就给 accpet connected 上来的client socket fd使用。就是配置中的 maxclients。所以 file 的 setsize 就是 maxclients+ RESERVERED_FDS (128).这就是EventLoop中的 file 以及 fired events 数组的 大小。(这里的数组表示一段连续可随机访问内存的说法,Redis中的comment一般称之为向量。)这种数组,以fd为索引。在初始时,这个状态flag 为AE_NONE。注册了事件了之后 AE_READABLE, AE_WRITABLE 等等。Redis 将事件注册状态记录在 file events中,同时向epoll注册,而触发状态记录在 fired 数组中。两者通过fd作为索引进行关联。关联之后,比较事件flag 去调用对应的 callback。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值