redis 单线程? 多线程?
redis 单线程? 多线程?
没有锁的竞争,没有线程的上下文切换。主要的性能瓶颈是内存或者网络带宽而非CPU
1.redis3.x版本,也就是大家口口相传的redis是单线程
2.redis4.x版本,严格意义上来说也不是单线程,负责处理客户端请求的线程是单线程,但是开始加了一点多线程的东西(异步删除)。
3.redis6.0版本,多线程io,但多线程部分只是用来处理网络数据的读写和协议解析
4.x版本异步删除的原因:删除大key
如果使用del
删除,会导致长时间阻塞,甚至崩溃。因为 del
命令在删除集合类型数据时,时间复杂度为 O(M)
,M 是集合中元素的个数。Redis 是单线程的,单个命令执行时间过长就会阻塞其他命令,容易引起雪崩。所以redis4引入新的命令unlink
,将键与键空间断开连接。实际的删除将稍后异步进行。(异步删库 flushall async,flushdb async)
redis6:
在Redis 6.0中新增了多线程的功能来提高I/O的读写性能,他的主要实现思路是将主线程的I/O读写任务拆分给一组独立的线程去执行,这样就可以使多个socket的读写可以并行化了,采用多路I/O复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络10的时间消耗),将最耗时的Socket的读取、请求解析、写入单独外包出去,剩下的命令执行仍然由主线程串行执行并和内存的数据交互。
综合上图,网络IO操作就变成多线程化了,其他核心部分(执行命令)仍然是线程安全的,是个不错的折中办法。
所以redis6,redis的工作线程是单线程的,也不会出现线程安全的问题,但是,整个redis来说,是多线程的。
redis6开启多线程IO功能
打开redis的配置文件:
配置文件说的很详细,当机器是4核,io的线程分配2个或者三个,当机器是8核,可以分配6核,io-threads
是配置线程数的配置项。
此外io-threads-do-reads
是打开多线程io的配置项,多线程io默认是no 关闭。
Redis的IO多路复用
Redis利用epoll来实现IO的多路复用,将连接信息和时间放到队列中,一次放到文件事件分派器,事件分派器将时间发给事件处理器。
Redis是跑在单线程中的,所有的操作都是按照顺序线性执行的,但是由于读写操作等待用户输入或输出都是阻塞的,所以I/O操作在一般情况下往往不能直接返回,这会导致某一文件的I/O阻塞导致整个进程无法对其它客户提供服务,而I/O多路复用就是为了解决这个问题而出现。
所谓I/O多路复用机制,就是说通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或写就绪) ,能够通知程序进行相应的读写操作。这种机制的使用需要select、poll、epoll来配合。多个连接共用一个阻塞对象,应用程序只需要在一个阻塞对象上等待,无需阻塞等待所有连接。当某条连接有新的数据可以处理时,操作系统通知应用程序,线程从阻塞状态返回,开始进行业务处理。
Redis服务采用Reactor的方式来实现文件事件处理器(每一个网络连接其实都对应一个文件描述符)
Redis基于Reactor模式开发了网络事件处理器,这个处理器被称为文件事件处理器。它的组成结构为4部分:
- 多个套接字
- IO多路复用程序
- 文件事件分派器
- 事件处理器
因为文件事件分派器队列的消费是单线程的,所以Redis才叫单线程模型。