一、简单介绍
众所周知,redis非常快,而且是单线程的,这里说的单线程是指单线程处理命令,而实际上redis是多线程的,很多异步操作都是给后台线程进行操作的。
高效的原因:
- 内存级,读写速度快,不受磁盘IO限制
- 数据结构设计简单以及高效,很多结构操作都是O(1)
- 单线程
(1)没有竞争,不需要锁
(2)没有线程切换,不需要上下文切换
(3)串行执行,保证每个操作都是原子性的 - IO多路复用架构,非阻塞IO
二、整体流程图
三、整体代码逻辑
3.1 首先建立监听套接字
main()
...
initServer() ->
...
//创建I/O多路复用器
aeCreateEventLoop() ->
aeApiCreate()
...
//创建监听socket
listenToPort() ->
...
anetTcp6Server()
...
anetTcpServer()
...
3.2 注册监听事件处理回调
initServer()
...
//注册接收链接事件处理回调
for (j = 0; j < server.ipfd_count; j++) {
if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE,
acceptTcpHandler,NULL) == AE_ERR)
{
serverPanic(
"Unrecoverable error creating server.ipfd file event.");
}
}
...
//注册定时任务定时器事件处理回调
aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL)
...
3.3 主循环
void aeMain(aeEventLoop *eventLoop) {
eventLoop->stop = 0;
while (!eventLoop->stop) {
aeProcessEvents(eventLoop, AE_ALL_EVENTS|
AE_CALL_BEFORE_SLEEP|
AE_CALL_AFTER_SLEEP);
}
}
aeProcessEvents()
...
numevents = aeApiPoll(eventLoop, tvp);
...
for (j = 0; j < numevents; j++) {
...
if (mask & AE_READABLE) {
fe->rfileProc(eventLoop,fd,fe->clientData,mask);
}
...
if (mask & AE_WRITABLE) {
fe->wfileProc(eventLoop,fd,fe->clientData,mask);
}
...
}
}
3.4 回调
3.4.1 接受链接,并注册read处理函数
fe->rfileProc(eventLoop,fd,fe->clientData,mask);
acceptTcpHandler() ->
acceptCommonHandler() ->
createClient() ->
connSetReadHandler(conn, readQueryFromClient);
...
conn->type->set_read_handler(conn, func);
...
其中type是在创建conn的时候使用的全局变量CT_Socket
connCreateAcceptedSocket() ->
...
connCreateSocket()
...
conn->type = &CT_Socket;
...
ConnectionType CT_Socket = {
.ae_handler = connSocketEventHandler,
.close = connSocketClose,
.write = connSocketWrite,
.read = connSocketRead,
.accept = connSocketAccept,
.connect = connSocketConnect,
.set_write_handler = connSocketSetWriteHandler,
.set_read_handler = connSocketSetReadHandler,
.get_last_error = connSocketGetLastError,
.blocking_connect = connSocketBlockingConnect,
.sync_write = connSocketSyncWrite,
.sync_read = connSocketSyncRead,
.sync_readline = connSocketSyncReadLine
};
static int connSocketSetReadHandler(connection *conn, ConnectionCallbackFunc func) {
if (func == conn->read_handler) return C_OK;
conn->read_handler = func;
if (!conn->read_handler)
aeDeleteFileEvent(server.el,conn->fd,AE_READABLE);
else
if (aeCreateFileEvent(server.el,conn->fd,
AE_READABLE,conn->type->ae_handler,conn) == AE_ERR) return C_ERR;
return C_OK;
}
3.4.2 回调read 进行数据读取
readQueryFromClient() ->
...
connRead()
...
3.4.3 解析命令
readQueryFromClient() ->
...
processInputBuffer()
...
while(c->qb_pos < sdslen(c->querybuf)){
...
if (c->reqtype == PROTO_REQ_INLINE) {
if (processInlineBuffer(c) != C_OK) break;
} else if (c->reqtype == PROTO_REQ_MULTIBULK) {
if (processMultibulkBuffer(c) != C_OK) break;
} else {
serverPanic("Unknown request type");
}
...
}
}
...
3.4.4 执行命令
readQueryFromClient() ->
...
processInputBuffer() ->
...
processCommandAndResetClient() ->
...
processCommand()
...
...
...
3.4.5 将响应写入队列中
processCommand() ->
...
call()
...
//根据不同的请求命令,回调不同的处理函数,这里使用get命令做示范
c->cmd->proc(c);
...
...
//t_string.c
getCommand() ->
getGenericCommand()
...
// 1.获取对应key的值
lookupKeyReadOrReply()
// 处理响应数据
addReply() ->
...
// 2.将此客户端连接加入到 链表server.clients_pending_write 中
prepareClientToWrite() ->
...
clientInstallWriteHandler()
...
listAddNodeHead(server.clients_pending_write,c); //一个客户端只会添加一次
...
// 3.将结果写入到待发送区
_addReplyToBuffer()
3.4.6 将数据发送给客户端
//在select之前将数据发送出去
扫描二维码关注公众号,回复:
12136549 查看本文章

beforeSleep() ->
...
handleClientsWithPendingWritesUsingThreads() ->
...
handleClientsWithPendingWrites()
...
// 遍历有待发送数据的客户端队列
listRewind(server.clients_pending_write,&li);
while((ln = listNext(&li))) {
client *c = listNodeValue(ln);
c->flags &= ~CLIENT_PENDING_WRITE;
listDelNode(server.clients_pending_write,ln);
...
/* Try to write buffers to the client socket. */
if (writeToClient(c,0) == C_ERR) continue;
...
}
...
...
...