Debug #
编译时会依赖一些库,具体参看 deps/README.md
# 调试时不要编译优化,默认是开启 `-O2` 编译优化选项的
make noopt
调试
gdb redis-server
全局变量 #
server: 最重要的一个全局变量,redisServer类型server.dbis an array of Redis databases, where data is stored. 默认16个server.commandsis the command table.server.clientsis a linked list of clients connected to the server.server.masteris a special client, the master, if the instance is a replica.server.elevent loop
server 启动简略流程 #
main
initServerConfig
populateCommandTable 加载命令到 server.commands
moduleInitModulesSystem
initServer
aeCreateEventLoop
listenToPort
anetTcpServer
aeCreateTimeEvent(serverCron) 定时任务事件回调
clientsCron 处理客户端日常工作,比如超时清理, server.clients
databasesCron key过期、渐进式rehash等
rdbSaveBackground
rewriteAppendOnlyFileBackground
replicationCron
clusterCron
modulesCron
createSocketAcceptHandler(acceptTcpHandler) 接收新连接
loadDataFromDisk
loadAppendOnlyFiles or rdbLoad
aeMain while 死循环
aeProcessEvents
aeEventLoop 事件循环 #
aeEventLoop 事件循环类型,server.el 变量
apidata是void *类型,指向底层实现的状态数据
多态,可以为不同的底层实现,通过宏定义在编译阶段优先使用 evport > epoll > kqueue > selectaeTimeEventtimer事件,如定时任务,是链表形式,通过aeCreateTimeEvent注册aeFileEvent文件描述符事件,是数组形式,通过aeCreateFileEvent注册aeFiredEvent哪些fd有新消息,由底层更新,是数组形式
启动流程的最后,aeMain 是一个死循环,不断执行 aeProcessEvents
beforesleep- 调用
aeApiPoll获取 fired events,然后执行该文件事件注册时的回调 aftersleepprocessTimeEvents遍历timer事件链表,执行回调
如果是定时任务,回调函数需要返回下一次毫秒数,否则认为是一次性任务,会删除该timer任务
处理连接请求 #
createSocketAcceptHandler通过aeCreateFileEvent给socket文件描述符创建事件acceptTcpHandler为其回调,当有新连接时,就会触发执行anetTcpAccept接受一个客户端连接请求,返回新的fdconnCreateAcceptedSocket根据客户fd,创建connection实例acceptCommonHandler- 判断是否超过
server.maxclients,否则限制连接 createClient根据connection创建client,并加入到server.clients链尾connSetReadHandler,回调是readQueryFromClient
下层自然是文件事件循环,aeCreateFileEvent
- 判断是否超过
connection 和 client 关系是,connection 是下层连接,client 是上层业务
client 在 connection 中包装为 void *private_data
处理指令请求 #
readQueryFromClient从 fd 中读取内容到c->querybufprocessInputBuffer会解析 RESP 数据为c->argcc->argvprocessCommand,根据server.commands静态命令表查找命令,c->cmd实际执行命令的是call,c->cmd->proc(c)- 各命令结果,一般通过
addReply写入到c->replyc->bufpos,并不是立即返回客户端
响应客户端时,是在下一个事件循环的 beforesleep 完成的,handleClientsWithPendingWritesUsingThreads
- 遍历
server.clients_pending_write,执行writeToClient - 如果一次发送不完,需要添加文件事件,当可写时,把剩余部分写完
installClientWriteHandler