这是我参与8月更文挑战的第18天,活动详情查看:8月更文挑战
redis server 和客户端建立连接,握手完毕,就会在 epoll 这里注册一个可读事件。
对于客户端命令处理的过程来说,主要分为 4 个阶段:
- 命令读取 → readQueryFromClient
- 命令解析 → processInputBufferAndReplicate
- 命令执行 → processCommand
- 结果返回 → addReply
命令读取
直接说流程:
-
分配读缓冲区 ← 读数据先缓冲到这
-
read() ⇒ 从 客户端socket 中读取数据
-
如果有异常数据
- 处理异常,结束执行返回
- 没有异常,继续
-
判断是否为主节点客户端
- 是 ⇒ 命令追加到同步缓冲区,修改同步 offset ⇒ 追加完,也继续下面操作
- 不是 ⇒ 继续下面
-
processInputBufferAndReplicate() 进行命令解析
命令解析
还是和 读取 一样,分主节点客户端和从节点:
-
无 CLIENT_MASTER 标记 → processInputBuffer() ⇒ 执行实际解析命令的函数
-
有 CLIENT_MASTER 标记
- processInputBuffer() ⇒ 执行实际解析命令的函数
- replicationFeedSlavesFromMasterStream() ⇒ 主节点接收到的命令同步给从节点
那么实际解析命令:processInputBuffer() 是怎么执行的?
-
整个 while() 不断读取读缓冲区的数据
-
识别命令 → 以 '*' 开头:
- 符合 RESP 协议
- 进而调用 processMultibulkBuffer() 解析命令
-
识别命令 → 不以 '*' 开头:
- 说明是 管道命令
- 命令之间使用:'\r\n' 分割开
- processInlineBuffer() 来解析实际命令
命令执行
-
调用 lookupCommand()
- 在 server 属性中的 commands 存储了相关的命令 → 对应的函数
-
进行检查:命令参数是否有效,内存使用情况,等等
-
开始执行命令:
- 看是否是:CLIENT_MULTI 标记。是 ⇒ 将命令入队,等待后续处理
- 没有标记 ⇒ call
- 会在 redisCommandTable 中找到命令对应的函数,然后通过定义的函数指针来完成
结果返回
- 调用 prepareClientToWrite() ⇒ 将待写入的数据加入到全局变量 server 的 clients_pending_write 中
- 接着调用 _addReplyToBuffer() ⇒ 返回的结果添加到客户端的输出缓冲区中