Redis新特性:100%掌握多线程模型
官方解答:
- 使用Redis时,几乎不会出现CPU成为瓶颈的情况。 Redis主要受到内存和网络的限制。
- 在典型的Linux系统上,Redis使用
管道化每秒可以处理100万个请求,因此如果应用程序主要使用O(N)或O(log(N))命令,则几乎不需要太多中央处理器。 - 采用单线后,可维护性高。虽然多线程模型在某些方面表现良好,但它给程序执行的顺序带来了不确定性,导致了一系列同时读写的问题,增加了系统复杂性,并可能导致线程切换甚至锁定。解锁和死锁造成的性能损失。
Redis通过AE事件模型和IO复用等技术具有非常高的处理性能,因此不需要使用多线程。
单线程机制大大降低了Redis内部实现的复杂度。 Hash、Rehash、LPush 等“线程不安全”命令的缓慢可以在没有锁的情况下执行。
在,马哥详细介绍了快的原理。
Redis 6.0之前,单线程意味着Redis只有一个线程运行?
没有,Redis在处理客户端请求时,包括获取(socket读)、解析、执行、内容返回(socket写)等,都是由一个顺序串行的主线程处理的。这就是所谓的“单线程”。
由于Redis在命令执行阶段使用单线程处理命令,所以并不是所有到达服务器的命令都会立即执行。所有命令最终都在 Socket 队列中。当socket可读时,就交给单线程事件处理。调度员一一执行。
![]()
此外,一些命令操作可以使用后台线程或子进程来执行(例如删除数据、生成快照、重写AOF)。
马老师,为什么Redis 6.0要引入多线程呢?
随着硬件性能的提升,Redis在读写网络IO时可能会出现性能瓶颈,即: 单线程处理网络读写的速度可能会提高底层网络硬件的速度。
读/写网络读/写系统调用在Redis执行过程中占用了大部分CPU时间。瓶颈主要在于网络的IO消耗。优化主要有两个方向:
- 提高网络IO性能。典型的实现是使用
DPDK替换内核网络堆栈。 - 使用多线程,充分利用多核,提高读写网络请求的并行度。典型的实现如
Memcached。
要添加对用户态网络协议栈的支持,需要修改Redis源码中与网络相关的部分(比如更改所有发送和接收网络请求的函数),这涉及到大量的开发工作。
而且新的代码也会引入新的bug,使系统不稳定。
所以Redis使用多个IO线程来处理网络请求,以提高网络请求处理的并行度。
需要注意的是,Redis多IO线程模型仅用于处理网络读写请求。对于Redis的读写来说,仍然是单线程处理。
这是因为网络处理往往是瓶颈,可以通过多线程并行处理来提高性能。
继续使用单线程执行读写命令,无需开发多线程安全机制来保证Lua脚本、事务等,实现更加简单。
架构图如下:
![]()
主线程和IO多线程是如何协同工作的?
如下图:
![]()
主进程:
- 主线程负责接收连接请求,获取
socket并将其插入到全局待读处理队列中; - 主线程轮询将可读的
socket分配给IO线程; - 主线程阻塞,等待IO线程读取
socket完成; - 主线程运行IO线程读取解析的Redis。请求命令;
- 主线程阻塞,等待IO线程将指令执行结果写回
socket完成; - 主线程清空全局队列,等待客户端后续请求。
想法:将IO读写任务从主线程拆分到一组独立的线程中处理,这样可以并行多个socket的读写,但Redis命令仍然是串行执行的主线程。
如何启用多线程?
Redis 6.0默认禁用多线程,仅使用主线程。要启用此功能,您需要编辑配置文件redis.conf:io-threads-do-reads yes。
代码又旧又湿。线程不是越多越好吗?
当然不是。关于线程数的设置,官方有建议:4核的机器建议2或3线程,8核的机器建议6线程。线程数必须小于机器的核心数。
线程数越多越好。官方认为超过八个线程基本没有意义。
启用多线程后,还必须设置线程数,否则没有效果。
io-threads 4
总结与思考
随着互联网的快速发展,企业互联网系统需要处理的在线流量不断增加。 Redis的单线程模式导致系统在网络I/O上消耗大量CPU时间,降低吞吐量。提高Redis的性能有两个方向:
- 优化网络I/O模块
- 提高机器内存的读写速度
后者取决于硬件的发展,有暂时没有解决办法。所以我们只能假设第一个。网络I/O优化可以分为两个方向:
- 零拷贝技术或者DPDK技术
- 利用多核优势
模型缺陷
Redis的多线程网络模型其实就是不是标准的多反应堆/主工模型。
在Redis的多线程解决方案中,I/O线程任务只是通过socket读取并解析客户端请求命令,但并不真正执行该命令。
所有客户端作业都要发回主线程执行,这样多核利用率不高,每次主线程都要忙着轮询并等待所有I/O线程完成后任务分配。只有完成任务后才能继续执行其他逻辑。
在我看来,Redis目前的多线程方案更多的是一种折衷的选择:既保持了原有系统的兼容性,又利用多核来提升I/O性能。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网