redis 6.0前不采用多线程,是因为单线程+i/o多路复用已足够高效,且多线程会引入锁竞争、缓存伪共享、原子性破坏及epoll不可并发调用等根本性问题。

Redis 6.0 之前的版本不是靠多线程防连接穿透,而是靠单线程 + epoll(或 kqueue)的 I/O 多路复用模型扛并发。它本身不拒绝超大规模连接,但“不适合”不是因为扛不住,而是在连接数极高、请求极碎(如大量小包 GET/SET)、网络吞吐饱和时,单线程成为瓶颈,且无法横向摊薄系统调用开销。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
accept 和 read/write 系统调用在单线程里串行排队
- 单线程主线程既要
accept新连接,又要read已建立连接的数据,还要解析、执行、write回复——全部挤在同一个事件循环里。 - 当连接数上万、每秒新建连接数百时,
accept调用可能被积压;更常见的是,大量空闲连接(比如长连接保活)+ 少量活跃连接混在一起,epoll_wait返回后仍需遍历所有就绪 fd,而单线程处理速度受限于 CPU 核心吞吐。 - 实测中,当网络带宽跑满(例如 10Gbps NIC),单线程
read/write调用本身就会吃掉 70%+ 的 CPU 时间,此时命令执行反而成了“配角”。
连接穿透(connection flooding)不是 Redis 自身能拦住的
- Redis 没有内置连接速率限制、IP 黑白名单或 TLS 握手卸载能力。所谓“防穿透”,实际依赖:
- 前置组件(如
nginx、haproxy、云 WAF)做连接限速和异常行为识别; - 内核参数(如
net.core.somaxconn、net.ipv4.tcp_max_syn_backlog)控制半连接队列; -
iptables或ebpf在协议栈早期丢包。
- 前置组件(如
-
Redis主线程一旦开始处理恶意连接(哪怕只是read一个字节就断开),就已消耗调度时间与缓存带宽——这正是“穿透”的代价。
多线程在 6.0 前不可行,核心卡在三个地方
-
dict(哈希表)操作非线程安全:像GET、SET这类读写共享redisDb.keys和redisDb.expires,若多线程并发访问,必须加锁;但细粒度锁(如 per-bucket)会引发false sharing(多个线程更新同一 cache line 中不同字段),实测性能反降 30%+。 -
lazyfree类后台任务(如UNLINK)虽从 4.0 起用子线程,但它们不参与请求路径,和客户端命令流完全隔离——你不能把command execution拆给多线程,否则WATCH/MULTI、LUA脚本的原子性就崩了。 -
IO 多路复用本身是单线程范式:一个epoll_fd无法被多个线程安全地epoll_wait——Linux 不允许,glibc 也不支持;强行多线程轮询会触发惊群(thundering herd)和大量无效唤醒。
真正容易被忽略的一点:Redis 6.0 的“多线程”只负责 socket 读写,命令执行仍是单线程。这意味着它缓解的是网络层压力,而非连接管理或逻辑穿透问题。如果你面对的是慢速客户端反复建连、发半包、故意延迟 ACK 这类攻击,再好的多线程 I/O 也救不了——该上 tcp_tw_reuse、syncookies 和连接池限流的地方,一个都不能少。










