Redis网络模型

发布于:2025-03-29 ⋅ 阅读:(35) ⋅ 点赞:(0)

Redis 网络模型详解

1. Redis 网络模型概述

核心特点

  • 单线程 Reactor 模式 (Redis 6.0 前)
  • 多线程 I/O 处理 (Redis 6.0+)
  • 基于事件驱动 (epoll/kqueue/select)
  • 高性能关键设计
    • 单线程避免锁竞争
    • 纯内存操作
    • 非阻塞 I/O

2. Redis 6.0 前的单线程模型

工作流程

  1. 初始化阶段:

    • 创建监听套接字
    • 绑定事件处理器(acceptTcpHandler)
    • 注册到事件循环(aeMain)
  2. 事件循环流程:
    [客户端请求]
    → [内核接收]
    → [epoll_wait 返回可读事件]
    → [Redis 主线程顺序处理命令]
    → [写回响应]

关键源码结构

// 事件循环核心结构
typedef struct aeEventLoop {
    int maxfd;
    aeFileEvent *events;  // 注册的事件
    aeFiredEvent *fired;  // 就绪的事件
    aeTimeEvent *timeEventHead; // 时间事件
} aeEventLoop;

// 事件处理器
typedef void aeFileProc(struct aeEventLoop *eventLoop, 
                       int fd, void *clientData, int mask);

优点

  • 无锁设计,避免竞争
  • 顺序执行,避免上下文切换
  • 实现简单,易于维护

缺点

  • 单线程无法利用多核CPU
  • 大键删除等操作会阻塞

3. Redis 6.0+ 的多线程模型

架构改进

  • 主线程:负责命令执行和事件调度
  • I/O 线程:处理网络读写(默认4个)
  • 后台线程:处理惰性删除等任务

工作流程

  1. 主线程接收连接请求
  2. 将就绪的socket分发给I/O线程
  3. I/O线程并行读取请求并解析
  4. 主线程串行执行命令
  5. I/O线程并行写回响应

关键配置
io-threads 4 # I/O线程数
io-threads-do-reads yes # 是否启用读多线程

线程分工图示

┌───────────────────────────────────────────────────────┐
│                   客户端请求队列                       │
└───────────────┬───────────────────┬───────────────────┘
                │                   │
                ▼                   ▼
┌───────────────────────┐   ┌───────────────────────┐
│      主线程           │   │      I/O线程组         │
│                       │   │  (默认4个,可配置)     │
│ 1. 接收新连接         │   │                       │
│ 2. 分发就绪socket     │   │ 3. 并行读取请求数据    │
│ 6. 执行命令           │   │ 4. 解析协议           │
│ 7. 准备响应           │   │ 8. 并行发送响应       │
│                       │   │                       │
└───────────┬───────────┘   └───────────┬───────────┘
            │                           │
            │  5. 将解析好的命令        │
            └───────────>───────────────┘

典型部署架构

           ┌───────────────┐
           │   客户端       │
           └──────┬───────┬┘
                  │       │
           ┌──────▼─────┐ │
           │   Redis    │ │
           │  Proxy层   │ │
           └──────┬─────┘ │
                  │       │
         ┌───────▼┐   ┌──▼───────┐
         │ Redis   │   │ Redis    │
         │ Master  │   │ Replica  │
         └─────────┘   └──────────┘

4. 事件处理机制

事件类型

  1. 文件事件 (套接字读写)

    • 使用epoll/kqueue实现
    • 响应式处理网络请求
  2. 时间事件 (定时任务)

    • 周期性事件(如serverCron)
    • 单次定时事件

事件处理器注册

// 示例:注册客户端连接处理器
aeCreateFileEvent(server.el, server.ipfd, AE_READABLE,
    acceptTcpHandler,NULL);

事件循环核心逻辑

void aeMain(aeEventLoop *eventLoop) {
    while (!eventLoop->stop) {
        aeProcessEvents(eventLoop, AE_ALL_EVENTS);
    }
}

5. 高性能网络设计要点

I/O 多路复用

  • Linux 使用 epoll
  • macOS 使用 kqueue
  • 其他平台 select

连接处理优化

  1. 可配置的最大连接数(maxclients)
  2. 客户端缓冲区管理
  3. 协议解析优化

网络参数调优
tcp-backlog 511 # TCP backlog队列
tcp-keepalive 300 # 保活检测
repl-disable-tcp-nodelay no # 禁用Nagle算法

6. 请求处理全流程

  1. 连接建立

    • acceptTcpHandler → createClient
    • 初始化客户端状态
  2. 命令读取

    • readQueryFromClient
    • 解析Redis协议
  3. 命令执行

    • processCommand → call
    • 执行前检查:
      • 内存限制
      • 命令权限
      • 集群重定向
  4. 响应返回

    • addReply → _addReplyToBuffer
    • 写入客户端输出缓冲区
  5. 连接关闭

    • freeClientAsync
    • 异步释放资源

7. 多线程模型源码分析

I/O 线程初始化

void initThreadedIO(void) {
    io_threads_active = 0;
    for (int i = 0; i < server.io_threads_num; i++) {
        pthread_create(&io_threads[i],NULL,
                      IOThreadMain,(void*)(long)i);
    }
}

I/O 线程主逻辑

void *IOThreadMain(void *myid) {
    while(1) {
        for (int j = 0; j < io_threads_list_len; j++) {
            redisAtomicIncr(io_threads_pending[myid],1);
            // 执行读/写操作
        }
    }
}

8. 性能对比数据

场景 单线程 QPS 多线程(4) QPS
GET 操作 120,000 210,000
SET 操作 110,000 190,000
混合读写 100,000 180,000

9. 生产环境调优建议

  1. 网络配置

    • 适当增加io-threads(不超过CPU核心数)
    • 调整TCP backlog
  2. 监控指标

    • instantaneous_ops_per_sec
    • blocked_clients
    • rejected_connections
  3. 问题排查

    • 慢查询监控(slowlog)
    • 客户端缓冲区监控
    • 连接数监控

10. 典型问题解决方案

连接数暴涨

  • 检查客户端连接池配置
  • 设置合理的timeout
  • 使用CLIENT KILL命令清理

网络延迟高

  • 启用TCP keepalive
  • 检查网络硬件
  • 考虑部署Proxy

CPU 瓶颈

  • 升级到Redis 6.0+
  • 增加I/O线程
  • 优化大key操作

网站公告

今日签到

点亮在社区的每一天
去签到