bigywater.tech
Redis · 106

Redis 单线程模型与后台线程

「Redis 是单线程的」这句话对也不对:命令确实是一个线程在执行,但进程里有好几个线程。这篇数一数线程,再用真正的压测工具把「单线程执行」的后果量出来:吞吐的上限在哪里、CPU 长什么样。

4 个线程
默认进程的线程数(1 主 + 3 后台);io-threads 4 时 7 个
1341k / 1350k
16 个连接 vs 64 个连接的 SET 吞吐(条/秒):不再增长
100%
压测时 Redis 进程的 CPU:一个核被占满

数线程

实测 · 本机执行输出
  默认                           线程数 = 4(含主线程)
  io-threads 4                 线程数 = 7(含主线程)
  io-threads 4 + appendonly yes 线程数 = 7(含主线程)

默认配置下进程有 4 个线程:主线程负责接收请求、执行命令、回复;另外 3 个是后台线程(第 107 篇看它们做什么)。io-threads 4 增加了 3 个 I/O 线程,总共 7 个(第 109 篇)。线程数取自 ps -M 与 top 的输出,macOS 上没法直接看线程名,所以「哪个是 BIO」这里没有验证。

吞吐的平台

redis-benchmark,SET,管道 16,50 万条,每格 2 次取中位
实测 · 本机执行输出
     连接数        吞吐(条/秒)
       1         508219
       4        1168454
      16        1340569
      64        1350238

1 个连接 508k 条/秒,4 个连接 1168k,16 个连接 1341k,64 个连接 1350k。前面是客户端不够快,加连接就涨;16 个连接之后到顶——服务器处理不过来了。(我先用 Python 线程做过一次类似实验,结果被 GIL 限制成客户端瓶颈,没有意义,换成了 C 写的 redis-benchmark。)

CPU:一个核

实测 · 本机执行输出
  top 三次采样(pid  %cpu  线程数): ['30145 0.0 4/1', '30145 71.2 4/1', '30145 99.9 4/1', '30145 99.5 4/1']

压测时 top 三次采样,Redis 进程的 CPU 到 99.9%(第一次采样在压测刚开始,数值低),线程数 4,同一时刻只有 1 个线程在运行。这是主线程跑满一个核。

这意味着什么

命令是串行执行的:一个慢命令占着主线程,所有客户端都排在后面(第 96 篇的排队实验、第 81 篇的 MIGRATE 阻塞)。单实例的吞吐上限就是这个平台,想更高只能多实例(分片/集群,第 68 篇)或开启 I/O 多线程分担网络读写(第 109 篇)。

分步演示:单线程执行

Redis 单线程模型与后台线程
本步的数据

    本文用到的工具与边界

    • 本机 macOS 27 / Redis 8.10.2 独立实例(本机回环端口,save 关闭),redis-cli 风格输出由自写的 RESP 客户端打印;计时用 time.perf_counter,数字每次运行会有小幅抖动。redis-benchmark -t set -P 16;线程数由 ps -M / top 得到
    • 没有验证:Linux 上的线程名与数量、后台线程各自的职责(第 107 篇)、命令执行期间主线程是否让出(有些命令分批执行)、超线程 / 多核机器上 I/O 线程的收益(第 109 篇)
    京ICP备2026067502号-1京公网安备11010502063487号