redis单线程模型(浅源码角度了解redis执行命令流程,解释redis 事件处理器,事件分配器等事件XXXX)

我们谈起redis线程模型或者执行流程经常在网上查到事件处理器,事件分派器等等等事件XXXX,如下图(看不懂直接跳到过看下文解说):

 

 实际上,这些糊弄玄虚的词汇反而加大我们学习成本。不如我们浅读源码了解这个单线程模型和请求执行过程。

redis启动初始化:

main入手,initServer()函数见注释。

int main(int argc, char **argv) {
   ...
   initServer();  //建立TCP连接,socket,bind,listen标准3步,返回文件描述符fd
    ...
   aeCreateFileEvent(fd, acceptHandler, ...);  
   ...
   aeMain();
   ...
}

第二部,asCreateFileEvent()函数将刚刚TCP返回的fd插入到一个叫asFileEvent的链表中,同时我们将这个fd(也就是第一个fd)绑定acceptHandler()函数用于监听到后面用户连接请求就调用这个函数。注意:我们后续插入到asFileEvent链表并且绑定相应的函数都是通过这个asCreateFileEvent()。至此我们形成下面这个格局:

之后asmian()函数一个死循环用于监听请求连接。

void aeMain(aeEventLoop *eventLoop)
{
    eventLoop->stop = 0;
    while (!eventLoop->stop)
        aeProcessEvents(eventLoop, AE_ALL_EVENTS);
}

小总结,这里我们完成了初始化,并且,第一个fd是我们redis唯一一个监听客户请求连接的fd。注意:fd就是我们IO多路复用的入参。所以,我们说redis是IO多路复用模式的。不了解IO多路复用可以看看我这篇文章IO多路复用(阻塞IO,非阻塞IO,select,poll,epoll)_量子学习法的博客-CSDN博客

当客户建立连接

好了,当第一个fd监听到客户端请求连接时会调用刚才绑定的acceptHandler(),这个函数执行后,我们会创建新的fd放在刚刚创建的asFileEvent链表下并绑定一个用户处理请求的函数readQueryFromClient()。结果如下:

所以同样的道理,后面用户有请求就调用 readQueryFromClient()这个函数。

readQueryFromClient()这个函数会去一张表中寻找命令所对应的函数,这部分用的编码技巧叫命令模式。

static struct redisCommand cmdTable[] = {
    {"get",getCommand,2,REDIS_CMD_INLINE},
    {"set",setCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
    {"setnx",setnxCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM},
    {"del",delCommand,-2,REDIS_CMD_INLINE},
    {"exists",existsCommand,2,REDIS_CMD_INLINE},
   ...
}

小总结: 至此redi启动到监听的轮廓我们已经形成,由于只有一个线程在监听这些描述符,并做处理。所以即使客户端并发地发送命令,后面仍然是依次取出命令,顺序执行。所以我们说redis是单线程模型的(包括redis 6.0)

好了,我们已经和客户端建立连接

  当客户发送请求,我们就会从readQueryFromClient()表中找到相应的函数。这个函数会应用很多redis底层数据结构。

  处理完成后,我们将响应发送回客户端。但是不是简单粗暴直接发送也不是开启一个新线程

仍然是调用aeCreateFileEvent将sendReplyToClient 函数挂在需要响应的客户端连接的文件描述符上。

static void addReply(redisClient *c, robj *obj) {
   ...
    aeCreateFileEvent(server.el, c->fd, AE_WRITABLE,
    sendReplyToClient, c, NULL) == AE_ERR);
}

  那什么时候发送给客户端?这里我们需要分情况讨论:

* 如果是读事件,就调用读事件的acceptxxxx方法,读事件处理完成后不直接响应,而是放到下一次select的写事件中响应

* 如果是写事件,就调用写事件的的acceptxxxx方法,返回响应

也就是说 只有写事件才会相应。

总结(我线下跟人聊到这一部分通常挺激动)

以上事情,我们解释了redis启动流程和单线程模型。下面,我们根据以上函数解释所谓的XXX事件。总体上,上面的事情可以有下面这张图概括:

 1,上文中asCreateFileEvent()用于插入到asFileEvent链表并且绑定相应的函数(acceptHandle(), readQueryFromClient())就是 事件处理器

2,上文监听事件的函数acceptHandle()就是连接应答处理器

3,处理请求函数readQueryFromClient()(刚才提到应用命令模式编码的函数)就是命令请求处理器

4听客户端响应(写事件)的文件描述符绑定的函数 sendReplyToClient()就是命令回复处理器。

5,这种一个负责响应 IO 事件,一个负责交给相应的事件处理器去处理,就叫做 Reactor 模式

参考文献:

https://blog.csdn.net/qq_38601777/article/details/91325622

https://mp.weixin.qq.com/s/keVI4Fn8N42VhIhODkuqBA

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值