引子
感觉这东西看过不记一下总会忘,所以手不能懒,及时总结一下。
本文主要针对Redis的服务端模型进行分析,力争能有总体的思路和部分细致的深入。源码版本3.2.8.
正文
Redis服务端一个典型的单线程reactor模型,使用I/O多路复用来完成对文件描述符的监听,然后主线程依次处理就绪的事件。
I/O多路复用
思路非常的简单,首先我们知道I/O多路复用有好几种方式,而这常常是和平台相关的,所以为了实现的简洁,扩展性,跨平台性,Redis在这里进行了一层封装,通过一套统一的API完成整个网络通信部分。
以Linux下的epoll为例,让我们来看一下。
typedef struct aeApiState {
int epfd;
struct epoll_event *events;
} aeApiState;
static int aeApiCreate(aeEventLoop *eventLoop);
初始化,主要是分配内存和调用epoll_create生成epoll监听fd,eventLoop结构体是服务端事件驱动的结构体。
static int aeApiResize(aeEventLoop *eventLoop, int setsize);
eventLoop记录了能监控的事件最大数,这里重新调整大小。
static void aeApiFree(aeEventLoop *eventLoop);
释放直接分配给eventLoop的内存空间
static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask);
向eventLoop里面添加要监控的事件,对于epoll来说就是epoll_ctl(EPOLL_CTL_ADD)
static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask);
删除监控的事件,对于epoll来说就是epoll_ctl(EPOLL_CTL_DEL)
static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp);
I/O多路复用的阻塞调用,对于epoll来说就是epoll_wait,第二个参数表示epoll要㩐待的最长时间。
static char *aeApiName(void);
返回封装的I/O多路复用实现,对于epoll来说就是返回“epoll”
而在选择I/O多路复用的实现时,是按照性能的从高到低。
在Redis的网络库ae.c最前面是这样的
#ifdef HAVE_EVPORT
#include "ae_evport.c" // Solaris
#else
#ifdef HAVE_EPOLL
#include "ae_epoll.c" // Linux
#else
#ifdef HAVE_KQUEUE
#include "ae_kqueue.c" // BSD
#else
#include "ae_select.c"
#endif
#endif