说Redis是单线程或者是多线程这种说法并不严谨,要拿版本说话,Redis的版本有很多3.x、4.x和6.x,版本不同架构也是不同的,不限定版本问是否单线程是不太严谨的。
- 版本3.x,最早版本,此时Redis是单线程的
- 版本4.x,严格意义来说此时Redis已经不是单线程了,而是负责处理客户端请求的线程是单线程,但是开始加了点多线程的东西(异步删除,aof)
- 版本6.x,以及2022年出的7.0之后的版本,告别了大家印象中的额单线程,用一中全新的多线程来解决问题
开始为什么Redis只支持单线程?
Redis是单线程主要是指Redis的网络IO和键值对读写是由一个线程完成的,Redis在处理客户端的请求时包括获取(socket读)、解析、执行、内容返回(socket写)等都由一个顺序串行的主线程执行,这就是所谓的单线程,这也是Redis对外提供键值存储服务的主要流程。
但Redis的其他功能,比如持久化RDB、AOF、异步删除、集群数据同步等等,都是由其他额外的线程执行的,Redis命令工作线程是单线程的,但是对于Redis整体来说,它其实是多线程的。
Redis 3.x 单线程时代但性能依旧很快的原因?
- 基于内存操作:Redis所有的数据都存在内存中,因此所有的运算都是内存级别的,多一他的性能比较高
- 数据结构简单:Redis的数据结构是专门设计的,而这些简单的数据结构的查找和操作的时间大部分复杂度是O(1),因此性能比较高
- I/O多路复用和非阻塞I/O:Redis使用I/O多路复用功能来监听多个socket连接客户端,这样就可以使用一个线程连接来处理多个请求,减少了线程切换带来的开销,同时也避免了I/O阻塞操作。(这个原因是Redis快最重要的原因)
- 避免上下文切换:因为是单线程模型,因此就避免了不必要的上下文切换和多线程竞争,这就省去了多线程切换带来的时间和性能上的消耗,而且单线程不会导致死锁问题的产生
Redis 4之前一直使用单线程的原因?
- 使用单线程模型是Redis的开发和维护更简单,因为单线程模型方便开发和调试
- 即使使用单线程模型也并法的处理多客户端的请求,主要是IO多路复用和非阻塞IO
- 对于Redis系统来说,主要的性能瓶颈是内存或者网络带宽而不是CPU
既然单线程这么好,为什么又要逐渐加入多线程的特性?
- 硬件的发展:目前CPU早已经是多核时代了,如使用单线程会对硬件资源的使用十分不充分
- 单线程存在的痛点如下:
例如正常情况下使用del命令很快就可以删除数据,而当被删除的key是一个非常大的对象时,例如包含了成千上万个元素的hash集合时,那么del指令就会造成redis主线程卡顿。这就是Redis 3.x单线程时代最经典的故障,大key删除的头疼问题
对于上面问题惰性删除 可以有效解决,于是在Redis4.0
中就增加了多线程模块,当然此版本中的多线程主要是为了解决删除数据效率比较低的问题。
sql
##异步删除
unlink k1
##异步清空库
flushdb async
将这些耗时的操作从主线程剥离让bio子线程来处理,极大减少主线程阻塞时间,从而减少删除导致性能和稳定性问题。