一、描述
1.linux下redis默认采用epoll来完成io的多路复用,将当前需要监听的io事件交由操作系统来完成。
当有关注的io事件到来的时候,操作系统则会通知用户程序相关的信息,这样即使采用单线程也能
监听多个io事件。
2.采用单线程来处理网络请求,除了1中epoll的io多路复用外,还有两个原因:
2.1 redis的数据结构是基于内存来实现的,因此其效率极高,即使单线程也能得到很高的吞吐量
2.2 redis基于单线程实现,那么就不需要关注线程安全的问题,这样可以极大的简化代码的编写难度
二、源码解析
1.服务入口src/server.c:main:
2.初始化服务src/server.c:initServer,其会调用aeCreateFileEvent,注册该监听的fd,并且会设置后续处理回调函数acceptTcpHanlder(红色):
3.注册监听文件fd,src/ae.c:aeCreateFileEvent,其是一个wrapper函数,其会调用实际的aeApiAddEvent完成最终的注册工作:
4.aeApiAddEvent有许多实现版本,如unix的kqueue,linux下的epoll,select和poll等,
而在我环境下,默认为epoll实现,src/ae_epoll.c:aeApiAddEvent:
5.启动服务,src/ae.c:aeMain,其会循环询问操作系统是否有io事件需要处理:
6.处理io事件,src/ae.c:aeProcessEvents,其会调用aeApiPoll(实际会到达src/ae_epoll.c:aeApiPoll的实现)询问是否有io事件到来,
而fe->rfileProc则是处理读事件的时候,如listen socket则是前面提到的acceptTcpHanlder,而connection socket,则会是 src/networking.c:readQueryFromClient:
后续更详细的留有时间再补充
三、总结:
由上面可以知道linux下,redis是采用epoll来实现io多路复用的,并且其会将不同类型的socket fd关联到不同的handler,这样在aeProcessEvents的时候可以统一代码,而不需要分支执行。后续有兴趣查看处理回调函数,无论是listen socket的acceptTcpHanlder和connection socket的readQueryFromClient都是一个线程一直执行下去,不会有新的业务线程来单独处理,从这里也能看出redis默认采用的是单进程单线程模式。