Redis真的是单线程的吗?

在学习redis的过程中老是听到:Redis快的原因之一是单线程模型,省去线程切换和竞争的性能开销,但是深入了解redis之后发现它并不是纯的单线程。

Redis 单线程指的是「接收客户端请求->解析请求 ->进行数据读写等操作->发送数据给客户端」这个过程是由一个线程(主线程)来完成的,这也是我们常说 Redis 是单线程的原因。

但是,Redis 程序并不是单线程的,Redis 在启动的时候,是会启动后台线程(BIO)的:

Redis 在 2.6 版本,会启动2个后台线程,分别处理关闭文件、AOF 刷盘这两个任务;.·Redis 在 4.0 版本之后,新增了一个新的后台线程,用来异步释放 Redis 内存,也就是 lazyfree 线程例如执行 unlink key/flushdb async/flushall async 等命令,会把这些删除操作交给后台线程来执行好处是不会导致 Redis 主线程卡顿。因此,当我们要删除一个大 key 的时候,不要使用 del 命令删除因为 del 是在主线程处理的,这样会导致 Redis 主线程卡顿,因此我们应该使用 unlink 命令来异步删除大key。

之所以 Redis 为「关闭文件、AOF 刷盘、释放内存」这些任务创建单独的线程来处理,是因为这些任务的操作都是很耗时的,如果把这些任务都放在主线程来处理,那么 Redis 主线程就很容易发生阻塞,这样就无法处理后续的请求了。

后台线程相当于一个消费者,生产者把耗时任务丢到任务队列中,消费者(BIO)不停轮询这个队列,拿出任务就去执行对应的方法即可。

虽然 Redis 的主要工作(网络 /O 和执行命令)-直是单线程模型,但是在 Redis 6.0 版本之后,也采用了多个 I/0 线程来处理网络请求,这是因为随着网络硬件的性能提升,Redis的性能瓶颈有时会出现在网络 //0 的处理上.

所以为了提高网络 I/0 的并行度,Redis 6.0 对于网络 I/0 采用多线程来处理。但是对于命令的执行Redis 仍然使用单线程来处理,所以大家不要误解Redis 有多线程同时执行命令。

Redis 官方表示,Redis 6.0 版本引入的多线程 I/0 特性对性能提升至少是一倍以上

Redis 6.0 版本支持的 I/0 多线程特性,默认情况下 1/0 多线程只针对发送响应数据(write client socket),并不会以多线程的方式处理读请求(read cient socket)。要想开启多线程处理客户端读请求,就需要把 Redis.conf 配置文件中的 io-threads-do-reads 配置项设为 yes。

复制代码
//读请求也使用io多线程
io-threads-do-reads yes

同时,Redis.conf 配置文件中提供了 10 多线程个数的配置项。

// io-threads N,表示启用 N-1 个 I/0 多线程(主线程也算一个 I/0 线程)io-threads 4

关于线程数的设置,官方的建议是如果为 4核的 CPU,建议线程数设置为 2 或 3,如果为8核 CPU 建议线程数设置为 6,线程数一定要小于机器核数,线程数并不是越大越好。

因此, Redis 6.0 版本之后,Redis 在启动的时候,默认情况下会额外创建6个线程(这里的线程数不包括主线程)

Redis-server: Redis的主线程,主要负责执行命令

bio_close_file、bio_aof_fsync、bio_lazy_free:三个后台线程,分别异步处理关闭文件任务、AOF刷盘任务、释放内存任务;

io thd 1、io_thd 2、io_ thd 3:三个1/0 线程,io-threads默认是4,所以会启动3(4-1)个//0多线程,用来分担 Redis 网络 //0 的压力。

为什么 Redis 中要使用 /0 多路复用这种技术呢?

因为 Redis 是跑在「单线程」中的,所有的操作都是按照顺序线性执行的,但是由于读写操作等待用户输入 或 输出都是阻塞的,所以I/O 操作在一般情况下往往不能直接返回,这会导致某一文件的 I/O阻塞导,致整个进程无法对其它客户提供服务。而 I/O 多路复用就是为了解决这个问题而出现的。为了让单线程(进程)的服务端应用同时处理多个客户端的事件,Redis 采用了 I/O多路复用机制。

这里"多路"指的是多个网络连接客户端,"复用"指的是复用同一个线程(单进程)。I/O多路复用其实是使用一个线程来检査多个 Socket 的就绪状态,在单个线程中通过记录跟踪每一个 socket(1/0流)的状态来管理处理多个I /O 流。如下图是 Redis 的I /O 多路复用模型:

相关推荐
松涛和鸣2 分钟前
72、IMX6ULL驱动实战:设备树(DTS/DTB)+ GPIO子系统+Platform总线
linux·服务器·arm开发·数据库·单片机
likangbinlxa19 分钟前
【Oracle11g SQL详解】UPDATE 和 DELETE 操作的正确使用
数据库·sql
r i c k1 小时前
数据库系统学习笔记
数据库·笔记·学习
野犬寒鸦1 小时前
从零起步学习JVM || 第一章:类加载器与双亲委派机制模型详解
java·jvm·数据库·后端·学习
IvorySQL2 小时前
PostgreSQL 分区表的 ALTER TABLE 语句执行机制解析
数据库·postgresql·开源
·云扬·2 小时前
MySQL 8.0 Redo Log 归档与禁用实战指南
android·数据库·mysql
IT邦德2 小时前
Oracle 26ai DataGuard 搭建(RAC到单机)
数据库·oracle
惊讶的猫2 小时前
redis分片集群
数据库·redis·缓存·分片集群·海量数据存储·高并发写
不爱缺氧i3 小时前
完全卸载MariaDB
数据库·mariadb
期待のcode3 小时前
Redis的主从复制与集群
运维·服务器·redis