Redis 6 引入 I/O 多线程,常被说成「让 Redis 多线程了」。它到底做了什么、能带来多少吞吐提升?这篇在本机上用 redis-benchmark 量三种负载,并用 INFO threads 的计数证明 I/O 线程确实分担了读写;同时坦率地说明:在压测与被测同机的条件下,收益很有限。
io-threads 50 连接 无管道 400 连接 无管道 50 连接 管道 16
1 89467 93406 1332741
2 89451 94883 1199520
4 93691 99463 1498127
8 95117 104661 1498127三种负载下 io-threads 从 1 到 8 的提升都不大:50 连接无管道 89k → 95k,400 连接无管道 93k → 105k,50 连接管道 16 1.33M → 1.50M(io-threads 8 与 4 相同,应是压测端上限)。io-threads 2 在管道 16 时反而低于 1(1.20M vs 1.33M),是单次测量的波动,我没有重复确认。
io-threads 1: io_thread_0:clients=1,reads=10127521,writes=10126010 io-threads 2: io_thread_0:clients=0,reads=0,writes=0 io_thread_1:clients=1,reads=10127521,writes=10126010 io-threads 4: io_thread_0:clients=0,reads=0,writes=0 io_thread_1:clients=1,reads=3325621,writes=3325124 io_thread_2:clients=0,reads=3410113,writes=3409600 io_thread_3:clients=0,reads=3391787,writes=3391286 io-threads 8: io_thread_0:clients=0,reads=0,writes=0 io_thread_1:clients=1,reads=1434808,writes=1434593 io_thread_2:clients=0,reads=1547269,writes=1547038 io_thread_3:clients=0,reads=1435633,writes=1435420 io_thread_4:clients=0,reads=1431821,writes=1431608 io_thread_5:clients=0,reads=1430638,writes=1430425 io_thread_6:clients=0,reads=1425922,writes=1425709 io_thread_7:clients=0,reads=1421430,writes=1421217
INFO 的 threads 段为每个线程列出处理的读/写次数。io-threads 1 时 io_thread_0(主线程)处理了全部读写;io-threads 4 时 io_thread_0 是 0,三个 I/O 线程各处理约三分之一;io-threads 8 时七个 I/O 线程平分。所以网络读写确实被挪出了主线程。
命令的执行仍是单线程(第 106 篇)。I/O 线程只在「网络读写占了主线程大部分时间」时才有明显收益:多连接、大 value、真实网卡的场景。而这次测量里压测端与 Redis 在同一台机器上,抢同样的 CPU,压测端自己往往先到上限(管道 16 时 io-threads 4 与 8 得到完全相同的数字就是迹象)。这里没有独立的压测机,也没有更大的 value(我最初还试过 4 KB,收益同样不明显,没有整理进表里),所以不能据此说 I/O 线程没用,只能说在这个条件下提升有限。