企业项目管理、ORK、研发管理与敏捷开发工具平台

网站首页 > 精选文章 正文

Redis命令执行过程_redis的命令大全

wudianyun 2025-09-01 16:12:08 精选文章 6 ℃

好的,我们来详细解析一下 Redis 服务器执行一个命令的完整流程。这个过程高效而精巧,是 Redis 能够实现高性能的关键所在。

其核心流程可以概括为以下几个阶段,我们结合流程图来看:

flowchart TD A[客户端发送命令请求] --> B[读取套接字<br>写入内核缓冲区] B --> C[数据从内核缓冲区<br>读取到用户空间] C --> D{解析请求<br>并查找命令实现} D -- 找到 --> E[执行前准备<br>(校验、审计、分析)] D -- 未找到 --> F[回复错误至输出缓冲区] E --> G[调用命令执行函数] G --> H[执行后续操作<br>(写入AOF/同步副本等)] H --> I[回复结果至输出缓冲区] F --> J I --> J[将输出缓冲区数据写入Socket] J --> K[通过网卡将结果返回给客户端]

整个流程始于客户端的请求,终于客户端的响应,中间绝大部分工作都在一个单线程中处理(核心的命令执行阶段)。下面我们分阶段进行详细说明。

第一阶段:客户端请求与读取 (Client Request & Reading)

  1. 建立连接

:客户端(如 redis-cli、应用程序中的 Redis 客户端库)通过 Socket 与 Redis 服务器建立连接。Redis 服务器使用 I/O 多路复用技术(如 Linux 下的 epoll)来同时监听成千上万个连接,等待命令请求到达。

  1. 命令到达

:客户端将命令按照 Redis 序列化协议(RESP)进行编码,并通过 Socket 发送出去。数据首先被送到服务器的内核网络缓冲区。

  1. 读取套接字

:Redis 的主事件循环(在 aeMain 函数中)通过 I/O 多路复用器监听到某个套接字变得可读(即有数据到达)。

    • 将命令请求从内核缓冲区读取到用户空间:Redis 会调用读事件处理器,将内核缓冲区中的命令数据读取到 Redis 服务器进程内存中的一个客户端专用输入缓冲区(client->querybuf)中。

第二阶段:命令解析与查找 (Command Parsing & Lookup)

  1. 解析命令

:Redis 将输入缓冲区中的原始请求数据按照 RESP 协议进行解析。它会拆解出命令(如 SET)、键(如 mykey)和值(如 Hello)等参数,并将其保存到客户端状态结构(redisClient)的 argv 和 argc 属性中。

    • 例如,解析 *3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$5\r\nHello\r\n 后,会得到 argv = ["SET", "mykey", "Hello"], argc = 3。
  1. 查找命令实现

:根据 argv[0](即命令名称 "SET"),在 Redis 的命令表中(一个字典,键是命令名,值是 redisCommand 结构)查找对应的命令实现函数。

    • 例如,找到 SET 命令对应的实现函数是 setCommand。

第三阶段:命令执行前准备 (Pre-execution)

  1. 执行前校验

:在真正执行命令前,Redis 会进行一系列检查:

    • 权限检查:检查客户端是否通过了认证(如果配置了 requirepass),以及是否有权限执行该命令(根据配置的 command 规则)。
    • 参数校验:检查传入的参数个数(argc)是否正确。例如,SET 命令至少需要两个参数。
    • 内存检查:如果服务器设置了最大内存,在执行可能增加内存使用量的命令前,会检查内存是否超限,如果超限且配置了相应的淘汰策略(maxmemory-policy),则会先尝试进行键淘汰。
    • 服务器状态检查:如果服务器正在进行数据加载(如启动时恢复 AOF 文件),则只能执行只读命令。
    • 如果任何一项检查失败,则会直接跳过执行步骤,将一个错误回复放入客户端的输出缓冲区

第四阶段:命令执行 (Execution)

  1. 调用命令实现函数

:所有前置检查通过后,Redis 调用在第二步中找到的命令函数(如 setCommand),并传入客户端状态(redisClient *c)作为参数。

    • 函数内部会执行具体的操作:例如,setCommand 会调用 setGenericCommand,最终调用底层的 dbAdd 或 dbOverwrite 等函数,将键值对写入到当前数据库(redisDb)的字典数据结构中。
  1. 执行后续操作

    • 记录慢查询:如果命令执行时间超过了 slowlog-log-slower-than 配置的阈值,该命令就会被记录到慢查询日志(Slow Log)中。
    • AOF 持久化:如果开启了 AOF(Append Only File)持久化,命令执行后,Redis 会将被执行的命令(或相应的协议内容)追加到 AOF 缓冲区(aof_buf)中。后续由另一个线程或事件循环在特定时机将其刷入(fsync)磁盘。
    • 主从复制:如果当前服务器是一个主节点(Master),命令执行后,它会将命令传播给所有从节点(Replicas)。

第五阶段:回复客户端与清理 (Reply & Cleanup)

  1. 将回复写入输出缓冲区

:命令执行函数会生成执行结果(例如,SET 命令成功返回 "+OK\r\n"),并将这个回复内容添加到当前客户端的输出缓冲区(client->buf 或 client->reply 链表)中。

  1. 将输出缓冲区数据发送给客户端

:Redis 的主事件循环会监听到客户端套接字变得可写,然后调用写事件处理器,将输出缓冲区中的数据通过 Socket 发送出去。

    • 数据先被写入内核的 Socket 发送缓冲区,最后由操作系统通过网络协议栈和网卡将结果返回给客户端。
  1. 清理工作

:命令执行完毕后,Redis 会做一些收尾工作:

    • 清空当前客户端的输入缓冲区(querybuf)。
    • 重置客户端状态(如将 argv 和 argc 置零),为处理下一条命令做准备。

关键设计要点与性能考量

  1. 单线程核心

命令的解析、执行、回复等核心操作都是在同一个主线程中顺序执行的。这避免了多线程的上下文切换和竞争条件,极大地简化了实现,保证了原子性。所谓的 "Redis 是单线程的" 主要指这个阶段。

  1. I/O 多路复用

:处理网络 I/O(监听和读写套接字)使用的是 I/O 多路复用技术,这使得单个线程能高效处理大量连接,这是高性能网络服务器的常见模式(如 Node.js)。

  1. 输入/输出缓冲区

:为每个客户端分配独立的缓冲区,使得可以异步地处理网络 I/O。读的时候可以一次性读取多个命令,写的时候可以等待套接字可写时再批量发送。

  1. 后台线程

:在更新的版本中(6.0+),Redis 引入了一些后台线程来处理一些耗时的操作,如:

    • UNLINK(异步删除大键)、FLUSHDB ASYNC
    • AOF 刷盘(可以配置为后台线程执行)。
    • I/O 读写(6.0+ 可以配置让后台线程处理读写 Socket,但命令执行依然在主线程)。

希望这个详细的流程解析能帮助你透彻地理解 Redis 的内部工作机制。

最近发表
标签列表