redis 命令处理过程

166 阅读2分钟

这是我参与8月更文挑战的第18天,活动详情查看:8月更文挑战

redis server 和客户端建立连接,握手完毕,就会在 epoll 这里注册一个可读事件。

对于客户端命令处理的过程来说,主要分为 4 个阶段:

  1. 命令读取 → readQueryFromClient
  2. 命令解析 → processInputBufferAndReplicate
  3. 命令执行 → processCommand
  4. 结果返回 → addReply

命令读取

直接说流程:

  1. 分配读缓冲区 ← 读数据先缓冲到这

  2. read() ⇒ 从 客户端socket 中读取数据

  3. 如果有异常数据

    1. 处理异常,结束执行返回
    2. 没有异常,继续
  4. 判断是否为主节点客户端

    1. 是 ⇒ 命令追加到同步缓冲区,修改同步 offset ⇒ 追加完,也继续下面操作
    2. 不是 ⇒ 继续下面
  5. processInputBufferAndReplicate() 进行命令解析

命令解析

还是和 读取 一样,分主节点客户端和从节点:

  1. 无 CLIENT_MASTER 标记 → processInputBuffer() ⇒ 执行实际解析命令的函数

  2. 有 CLIENT_MASTER 标记

    1. processInputBuffer() ⇒ 执行实际解析命令的函数
    2. replicationFeedSlavesFromMasterStream() ⇒ 主节点接收到的命令同步给从节点

那么实际解析命令:processInputBuffer() 是怎么执行的?

  1. 整个 while() 不断读取读缓冲区的数据

  2. 识别命令 → 以 '*' 开头:

    1. 符合 RESP 协议
    2. 进而调用 processMultibulkBuffer() 解析命令
  3. 识别命令 → 不以 '*' 开头:

    1. 说明是 管道命令
    2. 命令之间使用:'\r\n' 分割开
    3. processInlineBuffer() 来解析实际命令

命令执行

  1. 调用 lookupCommand()

    1. 在 server 属性中的 commands 存储了相关的命令 → 对应的函数
  2. 进行检查:命令参数是否有效,内存使用情况,等等

  3. 开始执行命令:

    1. 看是否是:CLIENT_MULTI 标记。是 ⇒ 将命令入队,等待后续处理
    2. 没有标记 ⇒ call
    3. 会在 redisCommandTable 中找到命令对应的函数,然后通过定义的函数指针来完成

结果返回

  1. 调用 prepareClientToWrite() ⇒ 将待写入的数据加入到全局变量 server 的 clients_pending_write
  2. 接着调用 _addReplyToBuffer() ⇒ 返回的结果添加到客户端的输出缓冲区中