1_Redis为什么快
Redis为什么快?
纯内存操作:
Redis利用内存进行数据存储,其操作基于内存读写,由于内存访问速度远超硬盘,使得Redis在处理数据时具有极高的读写速度。特别是对于简单的存取操作,由于线程在内存中执行的时间非常短,主要的时间消耗在于网络I/O,因此Redis在处理大量快速读写请求时表现出卓越的性能。单线程模型:
Redis采用单线程模型处理客户端请求,这一设计确保了操作的原子性,避免了多线程环境下的上下文切换和锁竞争问题。这使得Redis在处理命令请求时能够保持高度的确定性和一致性,同时也简化了编程模型,降低了并发控制的复杂性。IO多路复用技术:
Redis通过采用IO多路复用模型,如epoll,能够在一个线程中高效地处理多个客户端连接。单线程轮询监听多个套接字描述符,并将数据库的读、写、连接建立和关闭等操作转化为事件,通过自定义的事件分离器和事件处理器来高效地处理这些事件,从而避免了在等待IO操作时的阻塞。高效数据结构:
- Redis的整体设计围绕高效数据结构展开,其中包括但不限于全局哈希表(字典),该结构提供O(1)的平均时间复杂度,并通过rehash操作动态调整哈希桶数量,减少哈希冲突,采用渐进式rehash避免一次性操作过大导致的阻塞。
- 除此之外,Redis还广泛应用了多种优化过的数据结构,如压缩表(ziplist)用于存储短数据以节省内存,跳跃表(skiplist)用于有序集合提供快速的范围查询,以及其他如列表、集合等数据结构,均针对不同场景进行深度优化,确保了在读取和操作数据时的高性能。
IO多路复用技术
Redis通过使用IO多路复用技术(如epoll、kqueue或select等),在一个线程内同时监听多个socket连接,当有网络事件发生时(如读写就绪),再逐一处理。这样可以处理大量并发连接,并在单线程中高效地调度网络事件,使得单线程也能应对高并发场景。所以Redis服务端,整体来看,就是一个以事件驱动的程序,它的操作都是基于事件的方式进行的。Redis的事件驱动架构如图:
Redis的事件驱动架构是一种基于非阻塞I/O多路复用技术设计的高效处理并发请求的机制。在Redis中,事件驱动架构通过监听和处理各种网络I/O事件以及定时事件,使得Redis服务端能够在一个线程内高效地服务于多个客户端连接,并执行相关的命令操作。
事件驱动架构主要由以下几个组成部分构成:
套接字(Socket):
套接字是客户端与Redis服务端之间进行通信的基础接口,用于双向数据传输。I/O多路复用:
Redis服务端通过使用如epoll、kqueue等I/O多路复用技术,可以同时监听多个套接字上的读写事件。当某个客户端的套接字上有数据可读或可写时,内核会通知Redis服务端,而无需Redis反复检查每一个套接字状态。
Redis默认使用的IO多路复用技术确实是epoll。其主要优点如下:
并发连接限制
相比于select和poll,epoll没有预设的并发连接数限制,能够处理的并发连接数只受限于系统资源,适合处理大规模并发连接。内存拷贝优化
epoll采用事件注册机制,仅关注和通知就绪的文件描述符,无需像select和poll那样在每次调用时都拷贝整个文件描述符集合,从而减少了内存拷贝的开销。活跃连接感知
epoll提供了水平触发(level-triggered)和边缘触发(edge-triggered)两种模式,可以更准确地感知活跃连接,仅当有事件发生时才唤醒处理,避免了无效的轮询操作,提升了事件处理的效率。高效事件处理
epoll利用红黑树存储待监控的文件描述符,并使用内核层面的回调机制,当有文件描述符就绪时,会直接通知应用程序,从而减少了CPU空转和上下文切换的成本。
文件事件分派器(File Event Demultiplexer):
文件事件分派器是Redis事件驱动的核心组件,它负责将内核传递过来的就绪事件分发给对应的处理器。在Redis中,每个套接字都关联了一个或多个事件处理器,如客户端连接请求处理器、命令请求处理器和命令响应处理器等。事件处理器(Event Handlers):
事件处理器是Redis中处理特定事件的实际执行者。当文件事件分派器接收到一个就绪事件时,它会调用对应的事件处理器来执行相应操作,如读取客户端的命令请求,执行命令并对结果进行编码,然后将响应数据写回客户端。
而对于Redis中设计的事件主要分为两个大类:
文件事件(File Events):主要对应网络I/O操作,包括客户端连接请求(AE_READABLE事件)、客户端命令请求(AE_READABLE事件)和服务端命令回复(AE_WRITABLE事件)。
时间事件(Time Events):对应定时任务,如键值对过期检查、持久化操作等。所有时间事件都被存放在一个无序链表中,每当时间事件执行器运行时,会遍历链表并处理已到达预定时间的事件。
通过事件驱动架构,Redis能够在一个线程内并发处理大量客户端请求,而无需为每个客户端创建独立的线程。此外,由于Redis的高效内存管理、数据结构优化和单线程模型,避免了多线程环境下的锁竞争和上下文切换开销,从而实现了极高的吞吐量和响应速度。
在Redis 6.x版本中,虽然引入了多线程处理网络IO的部分,但核心命令执行依然保持单线程事件驱动的模型,以维持Redis原有的性能优势。
IO多路复用模型
IO多路复用的核心在于内核关注的是应用程序的文件描述符而非直接监控连接本身。客户端运行时产生的不同事件类型的套接字操作,会被内核捕获。在服务器端,I/O多路复用机制负责收集这些事件并将它们加入事件队列,随后通过文件事件分发器分发至对应事件处理器进行处理。
以Redis为例,在其单线程模型下,内核不间断地监测所有客户端socket的连接请求和数据传输状况。只要检测到任何socket上有待处理的动作,便会立即将控制权转交给Redis线程。这样一来,尽管仅依靠单线程,Redis仍能有效地处理多个并发的IO流。
select/epoll等IO多路复用技术提供了一种基于事件触发的回调模式,每当有不同事件发生时,Redis能够迅速调用相应的事件处理器,始终保持在处理事件的状态,从而提升了其响应速度。
由于Redis线程并不会因为等待某个特定socket的IO操作完毕而停滞,它可以流畅地在多个客户端间切换,即时响应每个客户端的不同请求,从而实现在单线程环境下对大量并发连接的有效处理和高并发性能。