一、 Redis 单线程 与 多线程 怎么说?
(1)重要的版本迭代
redis4 之前仅支持 单线程, redis 4之后慢慢 支持多线程, 直到redis6/7后才稳定
(2)redis 的 工作线程 是 单线程的
(命令) 工作线程 是指 处理Redis的 网络IO + 键值对读写 的一个线程
即redis 在处理 客户端请求时 ,所进行的 获取、 解析、 执行、 内容返回等 都是由一个顺序串行的主线程处理
(3)对于 整个Redis 来说,是多线程的
redis 的命令工作线程(单线程)+ 持久化RDB + AOF + 异步删除 + 集群数据同步 (均有额外的线程执行)等等
对于 整个Redis 来说,是多线程的
(4)redis3单线程时代 性能依旧快的 reason
1、基于内存操作: Redis 的所有数据都存在内存中 , 因此所有的运算都是内存级别的, 所以他的性能比较高
2、数据结构简单: Redis 数据结构的 查找和操作 时间复杂度大部分为 O(1) , 因此性能比较高
3、多路复用+非阻塞I/O : Redis 使用 I/O 多路复用功能 来监听多个 socket 连接客户端
可以使用一个线程连接来处理多个请求
减少线程切换带来的开销
避免 I/O 阻塞操作
4、避免上下文切换:单线程模型避免了不必要的 上下文切换 和 多线程竞争
省去了多线程切换 的时间与性能上的 消耗
而且 单线程不会导致 死锁问题
二、 为何 从单线程 过渡到 多线程
(1)单线程的痛点
redis3最经典的故障,BigKey删除问题
程序会等待很久 才会释放,类似加了一个 synchronized 锁
高并发场景下 会程序阻塞卡顿
如何解决?
使用 惰性删除 可以有效避免 Redis卡顿
Redis4 使用 unlink key / flushdb async / flushall async
三、 redis 6/7 的多线程特性 和 IO多路复用
(0)Redis的主要瓶颈
Redis的主要性能瓶颈: 系统内存大小 + 网络带宽(IO) + CPU(一般情况与CPU无关)
(1) IO 多路复用
0. bg
由于网络硬件的性能提升, 底层网络硬件处理速度 >> 单个主线程网络请求速度
so ===> redis 6/7 采用多个IO 线程来处理 网络请求
即 提高网络请求处理的并行度
1.处理流程
主线程 + IO线程 写作完成请求处理
四个阶段
2. 解释
1.FD (文件描述符/句柄)
2. 解释
IO 多路复用 :
一种同步的IO模型 ,实现一个线程监视多个文件句柄
当某个句柄就绪,通知相应的应用程序 进行读写操作
当没有时, 阻塞应用进程, 释放CPU资源
3. 概念
I/O: 网络I/O, 数据在 内核态 与 用户态 之间的读写操作(OS层面)
多路:多个客户端连接(连接指 套接字描述符,即socket or channel)
复用:复用一个 or more 线程
IO多路复用: 一个或一组线程 处理多个TCP 连接,使用单进程能够处理多个客户端连接
total: 一个服务端进程可以 同时 处理多个套接字描述符
实现IO 多路复用的模型有3种 : 可分 select -> poll -> epoll 阶段描述
(2)Unix网络编程中的五种 IO 模型
1. Blocking IO - 阻塞IO
2. NoneBlocking IO - 非阻塞IO
3. IO multiplexing - IO多路复用
4. signal driven IO - 信号驱动IO
5. asynchronous IO - 异步IO
(3) 设置多线程
在redis.conf中设置
四、面试题
1. redis到底是 单线程 还是 多线程?
redis4 之前仅支持 单线程, redis之后慢慢 支持多线程, 直到redis6/7后才稳定
2.IO多路复用 是什么?
I/O: 网络I/O, 数据在 内核态 与 用户态 之间的读写操作(OS层面)
多路:多个客户端连接(连接指 套接字描述符,即socket or channel)
复用:复用一个 or more 线程
IO多路复用: 一个或一组线程 处理多个TCP 连接,使用单进程能够处理多个客户端连接
total: 一个服务端进程可以 同时 处理多个套接字描述符
3.redis为什么这么快?
IO 多路复用 + epoll函数使用 (不仅仅是单线程命令 + redis 安装到内存中)
4.Subtopic