Redis为什么是单线程?为什么这么快?
Redis,作为一款高性能的内存数据库,广泛应用于各类高并发、高性能的场景中。一个常见的问题是,为什么Redis是单线程的?以及在单线程的情况下,Redis为什么还能保持如此高的速度?
1、Redis是不是单线程?Redis为什么是单线程的而不采用多线程呢?
这主要是基于一种客观原因来考虑的。因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了(毕竟采用多线程会有很多麻烦!)
1.1、Redis单线程的优劣势
单进程单线程优势
- 代码更清晰,处理逻辑更简单
- 不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗
- 不存在多进程或者多线程导致的切换而消耗CPU
单进程单线程弊端
- 无法发挥多核CPU性能,不过可以通过在单机开多个Redis实例来完善;
1.2 、为什么redis是单线程还能支持高并发呢?
redis 内部使用文件事件处理器 file event handler,这个文件事件处理器是单线程的,所以 redis 才叫做单线程的模型。
文件事件处理器:采用 IO 多路复用机制同时监听多个 socket,将产生事件的 socket 压入内存队列中,事件分派器根据 socket 上的事件类型来选择
对应的事件处理器进行处理。
文件事件处理器的结构包含 4 个部分:
- 多个 socket
- IO 多路复用程序
- 文件事件分派器
- 事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)
多个 socket 可能会并发产生不同的操作,每个操作对应不同的文件事件,但是 IO 多路复用程序会监听多个 socket,会将产生事件的 socket 放入队
列中排队,事件分派器每次从队列中取出一个 socket,根据 socket 的事件类型交给对应的事件处理器进行处理。
2、为啥edis单线程模型也能效率这么高?
- 纯内存操作
Redis的数据存储在内存中,读写操作非常快速。相比传统的基于磁盘的数据库,内存操作的延迟要低得多。这是Redis高性能的基础。
- 非阻塞IO多路复用机制
Redis采用了非阻塞IO多路复用机制,。底层是使用epooll+,把读写存都转换为事件,减少时间浪费。这种机制允许单个线程同时处理多个网络连接和IO操作,极大地提高了并发处理能力。底层通过将读写操作转换为事件,减少了时间浪费。
- 单线程避免了上下文切换和锁竞争
单线程模型避免了多线程环境下的上下文切换和锁竞争问题。上下文切换会带来额外的开销,而锁竞争可能导致性能瓶颈。单线程模型下,所有操作都是顺序执行的,无需加锁和解锁,避免了这些问题,也不存在多进程或者多线程导致的切换而消耗 CPU。。
Redis的数据结构并不全是简单的Key-Value,还有list,hash等复杂的结构,这些结构有可能会进行很细粒度的操作,比如在很长的列表后面添加一个元素,在hash当中添加或者删除一个对象。这些操作可能就需要加非常多的锁,导致的结果是同步开销大大增加。
- 高效的数据结构和算法
Redis内部使用了多种高效的数据结构和算法,例如哈希表、跳表、压缩列表等。这些数据结构设计精良,操作复杂度低,能够在O(1)或者O(log N)时间内完成大部分操作,进一步提升了性能。
- 基于vm的
Redis处理的速度很快,因为它是基于虚拟内存(VM的,并没VM没有使用os的交互方式。
关于VM与OS
有时有人会提到Redis的速度是因为它基于某种虚拟内存(VM),并且没有使用操作系统的交互方式。实际上,这是一种误解,Redis的虚拟内存(VM)机制与操作系统的虚拟内存有显著不同。Redis曾使用一种将不常用数据交换到磁盘的机制,并对数据进行压缩,减少I/O操作。与此不同,操作系统的虚拟内存基于4KB页面,这种粒度对于小对象来说过大,且会导致阻塞线程。因此,Redis通过压缩和非阻塞处理机制,提高了性能,而操作系统的虚拟内存管理可能带来响应延迟。尽管Redis后来弃用了虚拟内存机制,但其设计理念仍然有助于理解其高性能特点。