两个根本的原因,一是他是内存数据库,内存的访问速度天然的就是要快于磁盘很多倍,二是在于他的数据结构的设计,键值对按照一定的数据结构来组织,比如引入了哈希表和跳表,至于他的具体的数据结构的设计,可以参考上一篇文章Redis的数据结构去了解。
另外一个重要的原因就是 Redis 采用了多路复用机制,使其在网络 IO 操作中能并发处理大量的客户端请求,实现高吞吐率。这里我们重点了解一下他的多路复用机制。
Redis的IO多路复用机制
Linux 中的 IO 多路复用机制是指一个线程处理多个 IO 流,就是我们经常听到的 select/epoll 机制。简单来说,在 Redis 只运行单线程的情况下,该机制允许内核中,同时存在多个监听套接字和已连接套接字。内核会一直监听这些套接字上的连接请求或数据请求。一旦有请求到达,就会交给 Redis 线程处理,这就实现了一个 Redis 线程处理多个 IO 流的效果。
在请求到达时能通知到 Redis 线程,select/epoll 提供了基于事件的回调机制,即针对不同事件的发生,调用相应的处理函数。select/epoll 一旦监测到 FD (多个套接字)上有请求到达时,就会触发相应的事件。
这些事件会被放进一个事件队列,Redis 单线程对该事件队列不断进行处理。这样一来,Redis 无需一直轮询是否有请求实际发生,这就可以避免造成 CPU 资源浪费。同时,Redis 在对事件队列中的事件进行处理时,会调用相应的处理函数,这就实现了基于事件的回调。因为 Redis 一直在对事件队列进行处理,所以能及时响应客户端请求,提升 Redis 的响应性能。
最后有一点注意的要说一下,Redis 严格说来是多线程的,他的单线程主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的,这也是 Redis 对外提供键值存储服务的主要流程。不过 Redis 的其他功能,比如持久化、异步删除、集群数据同步等,其实是由额外的线程执行的。而且在Redis6.0版本以后,Redis 的网络 IO 的读写也是引入了多线程,进一步优化了网络读写的时候占用CPU时间片的问题。