TOC

Redis 真是单线程的?

Redis 核心模块是单线程架构,其高效利用 epoll I/O 多路复用机制实现了单线程高并发。
但是 Redis 服务有很多模块,整体上来说是多线程的。

top -Hbn1 -p `pidof redis-server`
top -Hbn1 -p `pidof redis-server`

top - 16:37:13 up 2 days,  6:38,  5 users,  load average: 0.10, 0.11, 0.17
Threads:   4 total,   0 running,   4 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni, 98.3 id,  1.7 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :   7869.6 total,    696.9 free,   2518.8 used,   4653.8 buff/cache
MiB Swap:   2048.0 total,   1016.4 free,   1031.6 used.   5004.1 avail Mem

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
 697076 redis     20   0   49988   3348   1840 S   0.0   0.0   0:08.79 /usr/bin/redis-server 127.0.0.1:6379
 697077 redis     20   0   49988   3348   1840 S   0.0   0.0   0:00.00 /usr/bin/redis-server 127.0.0.1:6379
 697078 redis     20   0   49988   3348   1840 S   0.0   0.0   0:00.00 /usr/bin/redis-server 127.0.0.1:6379
 697079 redis     20   0   49988   3348   1840 S   0.0   0.0   0:00.00 /usr/bin/redis-server 127.0.0.1:6379

ps -eLF | egrep "PID|redis-server" | grep -v grep

UID          PID    PPID     LWP  C NLWP    SZ   RSS PSR STIME TTY          TIME CMD
redis     697076       1  697076  0    4 12497  3344   3 15:41 ?        00:00:16 /usr/bin/redis-server 127.0.0.1:6379
redis     697076       1  697077  0    4 12497  3344   1 15:41 ?        00:00:00 /usr/bin/redis-server 127.0.0.1:6379
redis     697076       1  697078  0    4 12497  3344   0 15:41 ?        00:00:00 /usr/bin/redis-server 127.0.0.1:6379
redis     697076       1  697079  0    4 12497  3344   1 15:41 ?        00:00:00 /usr/bin/redis-server 127.0.0.1:6379

采用单线程模型也和 Redis 业务有关,几乎是纯 IO 操作,只消耗内存和网络带宽,不需要太多 CPU 资源。
单线程更安全,更简单,维护起来成本低。多线程除了线程切换消耗和锁的消耗之外,还会引入执行顺序的不确定性,增加了系统复杂度。

Redis 6.0.0 开始(2020/05/01),Redis 在核心模块中使用多线程

Ubuntu 官方源中的版本才 5.0.7,是享用不到了。
即便是 6.0+,多线程默认关闭(重点:为什么默认关闭?),据网上资料显示,需要配置相关参数:

# 默认为 1,就是和之前行为一致,主线程处理 IO
io-threads 4

# 如果 io-threads 大于 1,生成线程处理写操作,读操作继续在主线程处理
# 除非配置下面这行:
io-threads-do-read yes

PS:Redis 6.0 据说是 Redis 史上最大的一个发行版本,可能就是改多线程闹得。

改成多线程的原因:在一些复杂场景下,巨量 IO 操作(看这个默认配置,应该主要是写 Socket)也会导致 CPU 消耗太大,这种情况下,多线程带来的性能影响可以被忽略。
所以,Redis 新版允许 I/O 操作部分(包的读写和解析)改成多线程并行,数据访问部分维持单线程模型不变。
据说在一些基准测试中,开启多线程的 Redis 实例性能提升了一倍。
但是我想,可能绝大部分人不用关心这个变动。

参考资料与拓展阅读