为什么 Redis 比 MySQL 更快

单线程模型 Single-threaded read/write 使用多线程通常会带来更大的吞吐率和更短的响应时间,然而,使用多线程并不一定比单线程程序快。CPU在一个时间片中只执行一个线程,当内核线程切换时,它需要保存线程A的执行环境,然后加载线程B的执行环境。线程执行上下文切换的开销并不低,如果没有必要,应该尽量减少。而且,使用多线程往往会使设计更加复杂,要求我们在访问共享数据时更加小心–对数据加锁对Redis来说不是一个划算的选择。 多线程的坏处 上下文切换 访问共享数据时对数据加锁 绝大多数的Redis请求都是纯粹的内存操作,这个过程非常快,CPU并不是性能瓶颈,即使是单线程实例,单个实例也可以每秒处理数万个数据请求。对于更高的并发性要求,Redis还支持集群部署,即在一台或多台服务器上启动多个实例,以分担访问压力。 从产品定位上,Redis不是一个CPU密集性应用,单线程足以满足计算需求。 多路复用模型 IO Multiplexing 强烈推荐阅读原文 在类Unix系统中,内核使用File Descriptor,也即FD去标识一个文件或者一个I/O资源(网络套接字),这些FD被特定的进程所访问。使用不同的I/O模型去访问FD,所访问的模式也不同,常用包含五种I/O模型: 阻塞式I/O 非阻塞式I/O I/O复用 信号I/O 异步I/O 对于I/O多路复用,Linux提供了select/poll/epoll这三个系统调用,进程可以使用这些进程调用,从内核中监听多个文件描述符。 select/poll 使用线性结构存储进程监听的FD集合。即把文件描述符集合拷贝到内核中,让内核检查是否有事件产生,检查的方式很粗暴,通过遍历的方式去遍历文件描述符集合,当检查到有事件产生时,标记可读可写,接下来再把整个文件描述符集合拷贝到用户态中,然后用户态还需要通过遍历的方式找到可读可写的FD。 select使用BitsMap(最大监听1024个FD)、poll使用链表(突破了select的限制)。 epoll 使用红黑树监听待检测的FD。红黑树是个高效的数据结构,增删改一般时间复杂度是 O(logn)。通过对这棵黑红树的管理,不需要像 select/poll 在每次操作时都传入整个FD集合,减少了内核和用户空间大量的数据拷贝和内存分配。 结论: 我们每次向Redis请求,都会产生一个FD,如何支持数以万计的并发请求。这个问题可以转化为,Redis服务进程如何监听这么多的FD,答案是使用多路复用epoll来提升链接处理能力。这点与MySQL不同,MySQL是一个连接分配一个线程的模式。

May 20, 2023