Redis分析之整体架构

Redis 源码分析之服务端整体架构

redis是怎么启动的,任何的C语言系统肯定都是从main函数进入,我们又知道redis主要就是一个服务端程序,所以找server的main,在server.c里面找到main函数。

启动过程

下面看看main函数干了些什么:

c语言系统中一般会维护一个全局的数据对象去存储整个系统的关键数据,这里维护的就是一个server对象,系统数据都保存在这个结构体中,main函数要做的事就是初始化这个巨大的结构体。

  • 设置一下当前的时间,回调函数(zmalloc_set_oom_handler(redisOutOfMemoryHandler)),初始化hash种子等。
  • 初始化服务器的配置 initServerConfig();就是给这个巨大结构体里的数据赋值;
  • 解析命令行参数,比如输入redis -v -h 什么的,这是程序通过命令行读取一些配置的手段;
  • 从配置文件中读取配置并加载到内存,也就是通过配置继续初始化数据;
  • 初始化服务器,initServer();
  • 从磁盘中把数据加载到内存中loadDataFromDisk();
  • 所有的准备工作都干完之后,接下来就是循环干活了,比如接受客户端连接,处理各种命令的操作aeMain(server.el);很多程序都会有loop的字样,这个字样就是循环的意思,循环处理所有的事件,所以是eventloop。

循环基于的事件驱动模型

其实就是服务器的模型,redis的ae_epoll.c封装了epoll,redis在linux下运行就是封装了epoll,有三步:

  • 调用aeApiCreate创建一个epollfd对象,也就是平常使用epoll的过程
  • 然后使用aeApiAddEvent往里面添加事件,就是epoll_ctl函数的封装
  • 然后就调用wait等待事件响应处理就可以了

那么我们是在哪里初始化这个epoll的呢?想一想肯定是在初始化服务的时候,server.el = aeCreateEventLoop(server.maxclients+CONFIG_FDSET_INCR);

这就是server中维护的epfd,在调用上面的函数主要添加了读写事件和定时器事件,就是aefileevent和aetimeevent,在死循环过程中其实就是在处理这两类事件,redis对epoll所做的封装就是,实现了一个定时器,这个定时器可以帮助你把一些注册进定时器的事件注册进去,比如内存淘汰的时候,设置一个lru算法,就是通过定时器事件来发挥作用的。

主循环里现在就是这么干的:

  • 优先处理一些事件
  • 循环处理epoll中的就绪事件,也可能是用的select,kequeue
  • 处理定时器事件
void aeMain(aeEventLoop *eventLoop) {
    eventLoop->stop = 0;
    while (!eventLoop->stop) {
        if (eventLoop->beforesleep != NULL)
            eventLoop->beforesleep(eventLoop);//优先处理的事件
        aeProcessEvents(eventLoop, AE_ALL_EVENTS|AE_CALL_AFTER_SLEEP);//处理基本事件和定时器事件
    }
}

整体架构

服务器程序就是循环干活,会一直处理这些任务,这些任务从哪来,有一个池子放这些任务,比如epoll的事件池,当有任务要做的时候就把任务注册到这个池子里,或者注册定时器任务注册到定时器的池子里,注册就是回调的时候注册,比如,有连接事件发生,就会注册这个连接的写事件到池子里,这样当收到对方请求的时候,服务端就能处理了。

redis是一个单线程的服务器程序,所以并没有像其他程序一样,开启多个任务处理,所以,涉及到耗时的操作就会出现卡顿,比如调用keys*,且数据很多的时候,这时候redis必然是卡的,所以耗时操作需要注意。

连接的回调函数在哪

其实只要思路清晰,这时候就应该想到,接下来应该干嘛,服务端肯定早就设置了连接的回到函数,也就是开启监听端口之前,必然为连接事件设置了回调函数,在initserver过程里设置了acceptTcpHandler,当连接到来就会调用者函数建立连接了,然后就可以执行命令了。

后续

能力有限,后续应该就是客户端发送请求,然后server收到消息后,根据规定好的协议去解析,然后执行命令,有时间再去继续研究,就是RESP协议。

你可能感兴趣的:(组件,优秀开源源码分析)