Redis 启动运行流程图

graph TD A[启动Redis服务器] --> B[初始化服务器状态] B --> C[加载配置] C --> D[创建事件循环 aeEventLoop] D --> E[绑定监听端口] E --> F[注册时间事件] F --> G[注册文件事件:监听套接字] G --> H[进入主事件循环 aeMain] subgraph 事件循环 H --> I[aeProcessEvents] I --> J{阻塞等待事件} J -->|文件事件/时间事件| K[处理事件] end subgraph 文件事件处理 K --> L{事件类型} L -->|监听套接字可读| M[接受新连接 acceptTcpHandler] M --> N[创建客户端 redisClient] N --> O[注册客户端套接字读事件] L -->|客户端套接字可读| P[读取请求 readQueryFromClient] P --> Q[解析命令到 querybuf] Q --> R[处理命令 processInputBuffer] R --> S[执行命令 processCommand] S --> T[命令执行器 call] L -->|客户端套接字可写| U[发送响应 sendReplyToClient] end subgraph 命令执行 T --> V[查找命令字典 commandTable] V --> W[执行命令实现函数] W --> X[修改数据] X --> Y[写入响应缓冲区] Y --> Z[注册写事件] end subgraph 时间事件处理 K --> AA[执行 serverCron 任务] AA --> AB[清理过期键] AA --> AC[持久化操作] AA --> AD[主从复制] AA --> AE[集群心跳] AA --> AF[统计信息更新] end Z --> H U --> H AE --> H

关键流程说明

  1. 初始化阶段

    • 加载配置文件(redis.conf
    • 创建全局状态对象 redisServer
    • 初始化事件循环(aeEventLoop
    • 绑定监听端口(默认 6379)
    • 加载持久化数据(RDB/AOF)
  2. 事件驱动核心

    • 使用 I/O 多路复用(epoll/kqueue/select)
    • 两种事件类型:
      • 文件事件:网络 I/O(客户端连接/请求)
      • 时间事件:定时任务(serverCron
  3. 客户端连接处理

    // 伪代码示例
    void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
       int cfd = accept(fd, &cliaddr, &clilen); // 接受连接
       redisClient *c = createClient(cfd);      // 创建客户端对象
       aeCreateFileEvent(el, cfd, AE_READABLE, readQueryFromClient, c); // 注册读事件
    }
    
  4. 命令处理流程

    • 读取请求:readQueryFromClient() → 填充 querybuf
    • 协议解析:processInputBuffer() → 解析 Redis 协议
    • 命令查找:lookupCommand()commandTable 中查找
    • 执行命令:通过 call() 调用命令函数(如 setCommand, getCommand
  5. 时间事件(serverCron)

    int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
       // 每100ms执行一次
       databasesCron();     // 过期键清理
       triggerPersist();    // 触发RDB/AOF持久化
       replicationCron();   // 主从复制
       clusterCron();       // 集群管理
       updateStats();       // 更新统计信息
    }
    
  6. 响应返回

    • 结果写入 bufreply 缓冲区
    • 注册写事件 → sendReplyToClient() 异步发送
  7. 多线程扩展(Redis 6.0+)

    Main Thread: 
     接收连接 → 命令解析 → 命令执行 → 返回响应
               ↑
    IO Threads: 
     负责网络读/写(并行处理)
    

Redis处理客户端请求的流程

graph TD A[客户端连接] --> B[TCP连接建立] B --> C[创建client对象] C --> D[注册到I/O多路复用器] subgraph 事件循环 D --> E{等待事件} E -->|读事件| F[读取数据到输入缓冲区] F --> G[解析RESP协议] G --> H{命令完整?} H -->|否| E H -->|是| I[查找命令处理器] I --> J[执行命令] J --> K[操作内存数据库] K --> L[写入输出缓冲区] L --> M[注册写事件] E -->|写事件| N[发送响应数据] N --> O{发送完成?} O -->|否| E O -->|是| P[重置缓冲区] P --> Q{连接保持?} Q -->|是| E Q -->|否| R[关闭连接] end J -->|写命令| S[AOF持久化] S --> L J -->|主节点| T[复制传播] T --> L

核心流程说明:

  1. 连接建立阶段

    • 客户端通过TCP三次握手连接(端口6379)
    • Redis创建client对象(包含:socket fd、输入/输出缓冲区、状态标志)
    • 将socket注册到I/O多路复用器(epoll/kqueue)监听读事件
  2. 请求处理阶段

    • 读事件触发:从socket读取数据到querybuf(动态字符串实现)
    • 协议解析:按照RESP格式解析命令(支持Inline或Array格式)
      // RESP数组示例:*2\r\n$3\r\nGET\r\n$5\r\nmykey\r\n
      
    • 命令分发:在命令表(commandTable)中查找对应处理器
  3. 命令执行阶段

    • 核心操作:访问内存数据库(redisDb字典结构)
      • 读操作:直接访问dict获取数据
      • 写操作:修改dict并记录到AOF/传播到副本
    • 内存管理:使用jemalloc分配,淘汰策略(LRU/LFU)
    • 原子保证:单线程执行,无竞态条件
  4. 响应返回阶段

    • 写事件触发:将bufreply链表中的数据发送
    • 分块发送:网络拥塞时部分发送,保留剩余数据
    • 连接复用:重置缓冲区保留连接(keep-alive)
  5. 后台联动

    • 持久化:写命令触发AOF追加(writefsync
    • 主从复制:主节点将写命令传播到副本
    • 过期处理:访问时惰性删除+定期扫描

Redis持久化操作流程图

graph TD A[Redis持久化操作] --> B[RDB持久化] A --> C[AOF持久化] %% RDB持久化流程 B --> D1{触发条件} D1 --> |手动触发| D2[执行SAVE命令] D1 --> |手动触发| D3[执行BGSAVE命令] D1 --> |自动触发| D4[配置文件save规则满足] D2 --> D5[阻塞主进程<br>创建RDB文件] D3 --> D6[Fork子进程] D6 --> D7[子进程创建临时RDB文件] D7 --> D8[替换旧RDB文件] D8 --> D9[发送信号给主进程] D4 --> D6 %% AOF持久化流程 C --> E1[命令追加] E1 --> |写命令| E2[追加到AOF缓冲区] E2 --> E3{写入策略} E3 --> |appendfsync always| E4[每个命令同步写盘] E3 --> |appendfsync everysec| E5[每秒同步写盘] E3 --> |appendfsync no| E6[由系统决定] E4 --> E7[阻塞直到完成] E5 --> E8[异步线程执行] E6 --> E9[系统异步执行] E7/E8/E9 --> E10[AOF文件增长] E10 --> E11[AOF重写触发] E11 --> E12[Fork子进程] E12 --> E13[扫描内存数据] E13 --> E14[构建新AOF临时文件] E14 --> E15[替换旧AOF文件]

流程说明

RDB持久化流程

  1. 触发条件

    • 手动触发:SAVE(同步阻塞)或BGSAVE(异步)
    • 自动触发:满足redis.confsave <seconds> <changes>规则
  2. BGSAVE执行

    graph LR M[主进程] --> F[Fork子进程] F --> C[子进程创建temp.rdb] C --> W[写入内存数据快照] W --> R[重命名为dump.rdb] R --> S[发送完成信号] S --> M
    • 子进程完成前,新BGSAVE请求会被拒绝
    • 写时复制(COW)机制保证数据一致性
  3. RDB文件结构

    +---------------------+
    | REDIS | RDB版本 | 数据区 | EOF | 校验和 |
    +---------------------+
    

AOF持久化流程

  1. 命令追加
    • 所有写命令追加到aof_buf缓冲区
  2. 写入策略
    graph TB B[缓冲区] --> A[always] B --> E[everysec] B --> N[no] A -->|同步阻塞| D[磁盘] E -->|每秒异步| D N -->|系统异步| D
  3. AOF重写
    • 触发条件:文件增长超过阈值(auto-aof-rewrite-percentage)
    • 重写过程:
      • Fork子进程扫描内存数据
      • 生成新AOF临时文件(无冗余命令)
      • 重命名替换旧文件(主进程继续追加到新缓冲区)

关键配置参数

持久化类型 配置项 默认值 说明
RDB save 900 1 多组规则 自动触发条件
dbfilename dump.rdb dump.rdb RDB文件名
AOF appendonly yes no 启用AOF
appendfsync everysec everysec 写入策略
auto-aof-rewrite-percentage 100 100% 重写触发条件(增长比例)

混合持久化(Redis 4.0+)

graph LR H[混合持久化] --> I[RDB头部] H --> J[AOF尾部] K[加载时] --> L[先加载RDB部分] L --> M[重放AOF命令]

Redis清理过期键的详细运行流程图

graph TD A[开始] --> B{键访问操作?} B -->|是| C[惰性删除流程] B -->|否| D[定期删除流程] subgraph 惰性删除流程 C --> C1[执行命令前检查键是否过期] C1 --> C2{键已过期?} C2 -->|是| C3[异步删除键] C3 --> C4[向客户端返回空值] C2 -->|否| C5[正常执行命令] end subgraph 定期删除流程 D --> D1[定时任务启动] D1 --> D2{是否达到执行周期?} D2 -->|是| D3[随机抽取20个带TTL的键] D3 --> D4[删除本轮发现的过期键] D4 --> D5{删除比例>25%?} D5 -->|是| D6[继续抽样下一批] D5 -->|否| D7{达到时间上限?} D7 -->|是| D8[结束本轮清理] D7 -->|否| D3 D6 --> D9{已检查500键?} D9 -->|是| D8 D9 -->|否| D3 D8 --> D10[等待下一周期] end

关键机制说明:

  1. 惰性删除(被动清理)

    • 触发条件:任何键访问操作(GET/SET等)
    • 检查时机:命令执行前
    • 执行动作:若键过期则异步删除
    • 响应处理:向客户端返回空值(模拟键不存在)
  2. 定期删除(主动清理)

    • 触发条件:Redis定时任务(默认每秒10次)
    • 抽样规则:
      • 每轮随机抽取20个带TTL的键
      • 优先检查即将过期的键
    • 渐进式清理:
      • 当单轮删除比例 > 25% 时继续抽样
      • 单轮最大检查500个键
      • 单轮最大耗时25ms(避免阻塞主线程)
    • 退出条件:
      • 删除比例 ≤ 25%
      • 或达到时间上限
      • 或检查足够数量键

Redis主从复制的详细运行流程图

graph TD A[从服务器启动] --> B[发送 SLAVEOF 命令] B --> C[主服务器接收复制请求] C --> D{是否首次同步?} D -- 是 --> E[主进程 fork 子进程] E --> F[生成 RDB 快照] F --> G[缓存写命令到复制缓冲区] G --> H[发送 RDB 文件给从服务器] H --> I[从服务器清空旧数据] I --> J[加载 RDB 恢复数据] J --> K[发送复制缓冲区命令] K --> L[从服务器执行增量命令] D -- 否 --> M[检查 Replication ID/Offset] M --> N{偏移量是否在<br>复制缓冲区?} N -- 是 --> O[发送部分同步命令] O --> L N -- 否 --> P[触发全量同步] P --> E L --> Q[持续命令传播] Q --> R[主服务器实时发送写命令] R --> S[从服务器顺序执行命令] S --> T[保持数据最终一致] classDef highlight fill:#f9f,stroke:#333,stroke-width:2px; class E,F,G,H,J,K,O,P,R,S highlight;

关键流程说明:

  1. 初始化连接

    • 从服务器启动时执行 SLAVEOF master_ip master_port
    • 主服务器创建从服务器套接字并发送 PING 验证连接
  2. 全量复制(首次同步)

    graph LR E[主进程 fork] --> F[BGSAVE 生成 RDB] F --> G[缓存新写命令到复制缓冲区] G --> H[传输 RDB 文件] H --> J[从服务器 FLUSHDB 后加载 RDB]
    • 核心细节
      • RDB 生成期间主库继续处理命令
      • 复制缓冲区大小配置:client-output-buffer-limit slave
      • 传输使用专用通道(不阻塞主线程)
  3. 增量复制

    graph LR K[主服务器发送缓冲区命令] --> L[从服务器执行命令] L --> Q[进入稳定复制状态]
    • 复制原理
      • 主服务器维护 Replication Stream(命令流)
      • 从服务器记录复制偏移量(master_repl_offset
  4. 断线重连

    graph TB M{检查 Replication ID} -->|相同| N[检查复制偏移量] N -->|偏移量在缓冲区内| O[发送 PSYNC 部分同步] N -->|偏移量丢失| P[触发全量同步]
    • 关键参数
      • repl-backlog-size(缓冲区大小,默认1MB)
      • master_replid(复制ID)
  5. 持续同步

    • 主服务器每执行写命令,异步推送给从服务器
    • 从服务器按顺序执行命令(单线程)

Redis集群心跳发送的运行流程图

graph TD A[Redis节点启动定时心跳任务] --> B[心跳触发] B --> C[随机选择集群中的N个节点] C --> D1[目标节点1] C --> D2[目标节点2] C --> D3[...] C --> DN[目标节点N] subgraph 心跳发送与处理 D1 --> E1[发送PING消息<br>携带自身状态+部分节点状态] D2 --> E2[发送PING消息<br>携带自身状态+部分节点状态] DN --> EN[发送PING消息<br>携带自身状态+部分节点状态] E1 --> F1[接收方验证消息] E2 --> F2[接收方验证消息] EN --> FN[接收方验证消息] F1 --> G1[更新本地集群状态] F2 --> G2[更新本地集群状态] FN --> GN[更新本地集群状态] G1 --> H1[回复PONG消息] G2 --> H2[回复PONG消息] GN --> HN[回复PONG消息] H1 --> I1[发送方接收PONG] H2 --> I2[发送方接收PONG] HN --> IN[发送方接收PONG] I1 --> J1[更新本地集群状态] I2 --> J2[更新本地集群状态] IN --> JN[更新本地集群状态] end J1 --> K[判断节点状态变化] J2 --> K JN --> K K --> L{故障检测?} L -->|节点下线| M[标记疑似下线<br>PFail状态] L -->|超时未响应| M L -->|正常| N[更新心跳时间戳] M --> O[广播节点状态] O --> P[其他节点接收状态] P --> Q[收集故障报告] Q --> R{达到仲裁数?} R -->|是| S[标记实际下线<br>Fail状态] R -->|否| T[保持PFail状态] S --> U[触发故障转移] T --> V[继续监听] style A fill:#f9f,stroke:#333 style K fill:#ff9,stroke:#333 style M fill:#f96,stroke:#333 style S fill:#f44336,stroke:#333 style U fill:#4CAF50,stroke:#333

Redis集群心跳运行流程详解:

  1. 定时触发:每个节点启动定时任务(默认每秒10次)
  2. 节点选择:每次随机选择集群节点总数的1/10(至少3个节点)
  3. PING发送
    • 携带自身状态信息
    • 附带已知的其他节点状态(Gossip协议)
  4. 接收处理
    • 接收方验证消息有效性
    • 更新本地集群拓扑状态
    • 回复PONG消息(含自身状态)
  5. 状态更新
    • 发送方收到PONG后更新节点状态
    • 记录最新心跳时间戳
  6. 故障检测
    • 超时未响应节点标记为PFail(疑似下线)
    • 广播故障信息给其他节点
  7. 故障仲裁
    • 当多数主节点确认故障时
    • 节点标记为Fail(实际下线)
  8. 故障转移
    • 触发从节点晋升机制
    • 保证集群高可用

Redis统计信息更新运行流程图

flowchart TD A[Redis统计信息更新流程] --> B[客户端发送命令] B --> C[接收命令请求] C --> D[解析命令] D --> E[更新命令统计] E -->|更新命令调用次数| F[commandstats] E -->|更新总命令计数器| G[total_commands_processed] D --> H[执行命令] H --> I[更新内存统计] I -->|更新内存使用量| J[used_memory] I -->|更新峰值内存| K[used_memory_peak] H --> L[更新Keyspace统计] L -->|更新键数量| M[db0:keys] L -->|更新过期键数量| N[db0:expires] H --> O[更新网络统计] O -->|更新输入流量| P[total_net_input_bytes] O -->|更新输出流量| Q[total_net_output_bytes] H --> R[更新CPU统计] R -->|更新系统CPU时间| S[used_cpu_sys] R -->|更新用户CPU时间| T[used_cpu_user] B --> U[更新连接统计] U -->|更新总连接数| V[total_connections_received] U -->|更新当前连接数| W[connected_clients] H --> X[返回响应] X --> Y[更新请求延迟] Y -->|计算P50/P95/P99| Z[latency_percentiles] style A fill:#f9f,stroke:#333,stroke-width:2px

流程说明:

  1. 命令接收阶段

    • 客户端发送命令请求
    • Redis接收并解析命令
    • 更新全局命令计数器:total_commands_processed++
    • 更新命令专属计数器:commandstats[cmd_name].calls++
  2. 命令执行阶段

    • 内存统计
      • 动态更新内存使用量(used_memory)
      • 记录峰值内存(used_memory_peak)
    • Keyspace统计
      • 更新键数量(db0:keys)
      • 更新过期键数量(db0:expires)
    • 网络统计
      • 累计输入流量(total_net_input_bytes)
      • 累计输出流量(total_net_output_bytes)
    • CPU统计
      • 记录系统CPU时间(used_cpu_sys)
      • 记录用户CPU时间(used_cpu_user)
  3. 连接管理

    • 连接建立时:total_connections_received++
    • 实时维护:connected_clients
  4. 响应阶段

    • 计算请求延迟百分位值(P50/P95/P99)
    • 更新延迟统计(latency_percentiles)