当前位置: 首页 > news >正文

redis 6.0 多线程

Redis 6.0 的多线程并非指命令处理逻辑的多线程(命令执行仍然是单线程的),而是特指网络 I/O 的多线程,其核心目标是优化大量网络 I/O 带来的性能瓶颈,提升吞吐量,尤其是在高并发场景下。


Redis 6.0 之前 - 单线程模型与IO多路复用

在 6.0 之前,Redis 是著名的单线程模型(主要指的是处理用户请求的核心模块)。它之所以能高效处理海量并发连接,全靠其核心机制:IO 多路复用

IO多路复用 (I/O Multiplexing)
简单来说,它允许一个线程监控多个网络连接(Socket),当这些连接中有数据可读(客户端发来请求)或可写(可以发送响应)时,它会通知工作线程。在 Redis 中,最常用的是 epoll(Linux) 这样的系统调用。

单线程下的请求处理流程(经典模型):

  1. 监听与接收 (Listen & Accept)

    • 主线程通过 epoll 监听所有客户端连接(Listening Socket)上的 ACCEPT 事件。
    • 当有新连接到来时,主线程调用 accept() 系统调用,建立连接,并将新生成的客户端 Socket 也注册到 epoll 实例中,监听其上的 READ 事件。
  2. 读取请求 (Read Request)

    • 主线程通过 epoll 监听所有已建立连接的客户端 Socket 上的 READ 事件。
    • 当某个客户端发送了数据(一个命令请求),该 Socket 变为可读状态,epoll 会通知主线程。
    • 主线程会亲自、同步地 从内核缓冲区中将客户端的请求数据读取到用户空间,并解析命令。这个过程是 同步阻塞 的,虽然时间极短,但在海量连接同时发来请求时,它会成为瓶颈。
  3. 执行命令 (Execute Command)

    • 主线程根据解析出的命令,操作内存中的数据(如 GET, SET, LPUSH 等)。
    • 这一步始终是单线程的! 这是 Redis 保证原子操作和简单性的基石,避免了昂贵的锁开销。
  4. 写入响应 (Write Response)

    • 命令执行完毕后,会产生响应数据(如 "OK" 或具体的 value)。
    • 主线程将响应数据写入到该客户端 Socket 的内核发送缓冲区中。
    • 如果发送缓冲区已满,主线程会监听该 Socket 的 WRITE 事件,直到可写后再写入。这个写入过程也是 同步 的。

单线程模型的瓶颈:
在整个流程中,步骤 2(读请求)和步骤 4(写响应) 本质上是 I/O 操作,尤其是读取大量数据或向大量客户端发送响应时,它们会消耗可观的 CPU 时间。虽然每个操作的延迟是微秒级的,但在数十万并发连接下,这些微秒累积起来就非常可观了。主线程忙于这些 I/O 杂活,就会导致执行命令(核心业务)被延迟,整体吞吐量受限。


Redis 6.0 的多线程优化

Redis 6.0 引入了多线程来处理上述的 I/O 瓶颈。它增加了一种新的机制:I/O Threads

核心思想:
让主线程不再亲自执行所有耗时的读取请求和写入响应的操作,而是将这些操作分摊给多个 I/O 线程并行处理。主线程只负责最核心的命令执行。

关键特点:

  • 默认关闭:配置项 io-threads 4(表示使用 4 个 I/O 线程,通常 4-6 个就足够了,超过收益不大)。
  • 只处理 I/O:I/O 线程只负责读取客户端请求和回包(响应)绝不负责命令解析和执行
  • 主线程协调:主线程仍然等待 epoll 事件,但它现在是“管理者”,负责分配任务和执行命令。

多线程模式下的请求处理流程:

结合下图,可以更直观地理解整个流程:

flowchart TD A[客户端请求到达] --> B[主线程: epoll_wait 捕获事件] B -- 可读事件 --> C[主线程: 将Socket放入等待读队列] C --> D[主线程: 唤醒IO线程进行读取] D --> E[IO线程: 并行读取请求数据] E --> F[主线程: 等待所有IO线程读取完毕] F --> G[主线程: <b>单线程执行所有命令</b>] G --> H[主线程: 将响应Socket放入等待写队列] H --> I[主线程: 唤醒IO线程进行写入] I --> J[IO线程: 并行发送响应数据] J --> K[主线程: 等待所有IO线程写入完毕] K --> B

详细步骤解释:

  1. 读取阶段 (Read Phase)

    • 主线程通过 epoll_wait 捕获到一批有读事件(有请求到达)的 Socket。
    • 主线程不再自己读取,而是将这些 Socket分配到一个等待读取的队列中。
    • 主线程唤醒正在休眠的 I/O 线程(如果有的话)。
    • I/O 线程并行工作,各自从队列中取出 Socket,将请求数据从内核缓冲区读取到用户空间(即读到每个连接对应的 Client Buffer 中)。
    • 主线程等待所有 I/O 线程完成读取操作(自旋等待)。
    • 注意:命令的解析(Parsing)是由主线程在之后完成的。
  2. 执行阶段 (Execution Phase)

    • 这是最关键的一步,并且仍然是单线程的!
    • 所有客户端的请求数据都已就绪,主线程按顺序、串行地遍历所有客户端连接,解析其缓冲区的命令,执行命令,并将响应结果写入到各自的客户端响应缓冲区中。
    • 这一步保证了所有命令的原子性,不存在竞态条件。
  3. 写入阶段 (Write Phase)

    • 主线程执行完所有命令后,手中持有了一批需要发送响应的 Socket。
    • 主线程将这些 Socket分配到一个等待写入的队列中。
    • 主线程再次唤醒 I/O 线程。
    • I/O 线程并行工作,各自从队列中取出 Socket,将响应数据从用户空间的响应缓冲区写入到内核的网络发送缓冲区中
    • 主线程等待所有 I/O 线程完成写入操作。
    • 之后,主线程清空一些状态,重新回到 epoll_wait 循环,处理下一批事件。

总结与对比

特性 Redis 6.0 之前 (纯单线程) Redis 6.0+ (多线程I/O)
核心模型 单线程处理所有事情:网络I/O、命令执行 多线程I/O,单线程命令执行
优势 无锁,绝对原子性,模型简单 高并发下吞吐量显著提升,尤其利于大键或管道批处理
瓶颈 网络I/O(读请求/写响应)成为主要瓶颈 命令执行本身(CPU密集型操作)可能成为新瓶颈
适用场景 并发连接数不是极端高,或命令本身开销大的场景 需要应对极高网络吞吐量的场景

简单比喻:

  • 单线程Redis:像一个全能服务员,从迎客、点菜、炒菜、上菜、收银全是一个人干。人一多就忙不过来。
  • 多线程I/O的Redis:像一家餐厅。主线程是唯一的大厨(炒菜)I/O线程是一群服务员。服务员(I/O线程)负责迎接客人、记录点单(读请求)和上菜(写响应)。而核心的炒菜工作(执行命令)永远由大厨一个人完成,保证味道一致(原子性)。这样效率就高多了。

因此,Redis 6.0 的多线程是在保持其核心数据操作原子性和简单性的前提下,对性能瓶颈的一个精准打击,极大地提升了其在现代高性能网络环境下的竞争力。

http://www.hskmm.com/?act=detail&tid=13575

相关文章:

  • docker 常用命令与端口映射
  • linux重启mysql服务,几种常见的方法
  • opencv学习记录3
  • 统计分析神器 NCSS 2025 功能亮点+图文安装教程
  • mysql常用语句,常用的语句整理
  • 当写脚本循环更新几百万数据发现很慢怎么办 - 孙龙
  • 服装采购跟单系统的高效管理实践 - 详解
  • 和汽车相关的国内期刊
  • 服务器CPU、内存、磁盘、网络使用率,东方通CPU使用率东方通内存使用率监控脚本
  • 3 网络基础知识+web基础知识+部署Server
  • wxpython图形界面_01_最小基本结构
  • 服务器总资源监控脚本
  • 一个身体,两个身体
  • 006_字典操作
  • 简单理解java虚拟机
  • 东方通中间件嵌入式监控脚本
  • 004_元组操作
  • 个人作业-第二次软件工程作业
  • 代码流水线
  • 洛谷题单指南-进阶数论-P1516 青蛙的约会
  • electron中的几个概念
  • 实用指南:告别IP被封!分布式爬虫的“隐身”与“分身”术
  • 从 “盲调” 到 “精准优化”:SQL Server 表统计信息实战指南
  • 别的摄像机都能国标GB28181注册上,就这台海康摄像机注册不上来,国标配置都反复检查没问题
  • 保护眼睛小程序
  • CSP-2025游寄
  • [::-1]的用法
  • 003_for循环操作列表和元组
  • linux 文件传输命令
  • 新手也能轻松上手!midas Gen 2019 安装详细图解