项目项目中应用到了redis,对其基于内存的nosql数据库比较感兴趣,打算读一下redis源码,写到哪里算哪里。第一篇是关于redis的网络模型:
redis网络模型采用epoll 异步事件处理机制,针对客户端的读写均是采用单线程的形式操作,于是不存在数据安全性的问题,即多个客户端同时修改某一个相同的key。为什么采用单线程模型,也许是因为redis针对数据的操作均是基于内存操作,没有涉及到磁盘I/O。当然数据持久化会涉及到磁盘I/O,数据持久化会在后面陆续读源码,记录redis的持久化过程和客户端数据读写同时发生时的处理机制。
1、server.el = aeCreateEventLoop(server.maxclients+1024);
此函数在initServer()中调用,用于创建epoll 事件结构体。
使用的数据结构是aeEventLoop ,结构如下:
typedef struct aeEventLoop {
// 目前已注册的最大描述符
int maxfd; /* highest file descriptor currently registered */
// 目前已追踪的最大描述符
int setsize; /* max number of file descriptors tracked */
// 用于生成时间事件 id
long long timeEventNextId;
// 最后一次执行时间事件的时间
time_t lastTime; /* Used to detect system clock skew */
// 已注册的文件事件
aeFileEvent *events; /* Registered events */
// 已就绪的文件事件
aeFiredEvent *fired; /* Fired events */
// 时间事件
aeTimeEvent *timeEventHead;
// 事件处理器的开关
int stop;
// 多路复用库的私有数据
void *apidata; /* This is used for polling API specific data */
// 在处理事件前要执行的函数
aeBeforeSleepProc *beforesleep;
} aeEventLoop;
aeEventLoop *aeCreateEventLoop(int setsize) {
aeEventLoop *eventLoop;
int i;
// 创建事件状态结构
if ((eventLoop = zmalloc(sizeof(*eventLoop))) == NULL) goto err;
// 初始化文件事件结构和已就绪文件事件结构
eventLoop->events = zmalloc(sizeof(aeFileEvent)*setsize);
eventLoop->fired = zmalloc(sizeof(aeFiredEvent)*setsize);
if (eventLoop->events == NULL || eventLoop->fired == NULL) goto err;
eventLoop->setsize = setsize;
eventLoop->lastTime = time(NULL);