redis之单线程命令处理_风雪舞者的技术博客_51CTO博客
一、简单介绍
众所周知,redis非常快,而且是单线程的,这里说的单线程是指单线程处理命令,而实际上redis是多线程的,很多异步操作都是给后台线程进行操作的。 高效的原因:
-
内存级,读写速度快,不受磁盘IO限制
-
数据结构设计简单以及高效,很多结构操作都是O(1)
-
单线程 (1)没有竞争,不需要锁 (2)没有线程切换,不需要上下文切换 (3)串行执行,保证每个操作都是原子性的
-
IO多路复用架构,非阻塞IO
二、整体流程图
三、整体代码逻辑
3.1 首先建立监听套接字
main() ... initServer() -> ... //创建I/O多路复用器 aeCreateEventLoop() -> aeApiCreate() ... //创建监听socket listenToPort() -> ... anetTcp6Server() ... anetTcpServer() ... 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.
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) ... 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.
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); } ... } } 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.
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; } 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.
3.4.2 回调read 进行数据读取
readQueryFromClient() -> ... connRead() ... 1.2.3.4.5.
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"); } ... } } ... 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.
3.4.4 执行命令
readQueryFromClient() -> ... processInputBuffer() -> ... processCommandAndResetClient() -> ... processCommand() ... ... ... 1.2.3.4.5.6.7.8.9.10.11.
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() 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.
3.4.6 将数据发送给客户端 //在select之前将数据发送出去
登录后复制
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; ... } ... ... ... 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.