1.单线程架构
Redis基于Reator模式开发了自己的网络事件处理器:文件事件处理器。其架构图如下:
文件事件处理器的四部分:套接字、I/O多路复用程序、文件事件分派器和事件处理器。
1.1.套接字Socket
- 文件事件就是对套接字的抽象,每当一个套接字准备好执行连接、写入、读取、关闭等操作时,都会产生一个文件事件。
- 因为一个Redis服务器会连接多个套接字,所以多个文件事件可能会并发出现。
1.2.I/O多路复用程序
- I/O多路复用程序,负责监听多个套接字,按照处理顺序,将套接字存放在一个队列中。
- 套接字队列以有序(sequentially)、同步(synchronously)、每次一个套接字的方式向文件事件分派器传送套接字。
- 当上一个套接字产生的事件被处理完毕之后, I/O 多路复用程序才会继续向文件事件分派器传送下一个套接字。
- 关于I/O多路复用的优势后续章节会细说。
1.3.文件事件分派器
文件事件分派器接受I/O多路复用程序传递的套接字,根据套接字的事件类型,调用相应的事件处理器进行处理。
1.4.文件事件处理器
本文不打算对文件事件处理器进行过多的描述,只是几类处理器进行简单的说明:
- 连接应答处理器:对连接服务器的各个客户端进行应答。
- 命令请求处理器:接收客户端传来的命令请求。
- 命令回复处理器:向客户端返回命令的执行结果
- 复制处理器:当主服务器和从服务器进行复制操作时, 主从服务器都需要关联此处理器。
- 等等…
2.I/O多路复用
I/O多路复用是其中的一种高级I/O模型,英文为I/O multiplexing,multiplexing
译为多路复用
、多路传输
的意思。
作为高性能服务,Redis服务器,同时连接多个连接(Socket)是在正常不过的事情。
此时,如何处理多个连接呢?
- 方式一:传统的多进程并发模型 ,每进来一个新的I/O流会分配一个新的进程管理。
- 方式二:I/O多路复用 ,单个线程,通过记录跟踪每个I/O流的状态,来同时管理多个I/O流 。
对I/O多路复用的分词理解:
- I/O: 这是一种处理I/O的高级模型。
- 多路: 多个I/O流,多个Socket连接。
- 复用:多个Socket连接共用单个线程。复用方式:单个线程,记录跟踪每个I/O流的状态,通过
开关控制
,每次处理一个I/O流。
I/O多路复用示例图:
select、poll、epoll
I/O多路复用模型是一种理论上的模型,select、poll和epoll都是这个模型的具体实现。
select
是第一个实现 (1983 左右在BSD里面实现的),它存在很多问题:
- 会修改传入的参数数组,这个对于一个需要调用很多次的函数,是非常不友好的。
- select 只能监视1024个链接。
- 任何一个I/O流出现了数据,select 仅仅会返回,但是并不会告诉哪个I/O流上有数据,需要自己去遍历查找。
- select 不是线程安全的。
poll
是14年以后(1997年)一帮人实现的,修复了select
的很多问题:
- 不再修改传入的参数数组。
- 去掉了select只能监视1024个链接的限制。
epoll
是5年以后, 在2002, 大神 Davide Libenzi 实现的,继续修复了select
和poll
的绝大部分问题:
- 不仅告诉sock组里面数据,还会告诉具体哪个sock有数据。
- 线程安全的。
epoll
本身还有一个致命的问题:只有linux支持。BSD(是Unix的衍生系统)上面对应的实现是kqueue。
下图给出了poll
和epoll
的性能测试(横轴为连接数,纵轴为每秒处理请求的数量):
可以看到,epoll每秒处理请求的数量基本不会随着链接变多而下降的。
3.影响 Redis 性能的因素(Redis为什么这么快)
参考章节1和2,可以总结提升Redis性能的主要因素如下:
- 完全基于内存:Redis是纯内存数据库,绝大部分请求都是纯内存操作。内存响应时间大约为百纳秒级别,每秒可进行几百万级别的操作。
- 非阻塞多路复用IO:Redis使用
epoll
作为I/O多路复用技术的实现,通过单线程来处理多个链接请求,减少网络IO的耗时。 - 事件处理模型:Redis自身的事件处理模型将epoll的连接、读写、关闭都转换为文件事件,进一步减少在网络IO上的耗时。
- 单线程模型:Redis采用单线程模型,简化了数据结构和算法的实现,避免了线程切换、调度(锁)、竞争产生的消耗。
- 数据结构与特殊处理:Redis数据结构简单,数据操作也简单,而且还专门针对数据指定了压缩、优化、跳表等特殊处理。
特别的,单线程会有一个问题:对于每个命令的执行时间是有要求的。如果某个命令执行过长,会造成其他命令的阻塞,对于Redis这种高性能的服务来说是致命的,所以Redis是面向快速执行场景
的数据库。这一点非常关键。
4.Redis的性能(Redis到底有多快)
Redis 自带了一个叫 redis-benchmark
的工具来模拟 N 个客户端同时发出 M 个请求,即对QPS进行自测。
首先来看一张官方提供的测试结果:
上图中,横轴是连接数,纵轴是每秒处理的请求时。由图中可知:
- Redis的最大QPS能够到达120000+q/s。
- 当连接数在10000以下时,Redis的QPS超过100000q/s。
- 当连接数达到60000时,Redis的QPS仍有50000q/s。