前言
上一篇介绍了 Redis 定义的九大数据类型。这节开始介绍 Redis 中的线程模型:单线程模型和多线程模型。
单线程模型
Redis 的单线程,主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的。但其他部分功能,比如持久化、异步删除、集群数据同步等,其实是由额外的线程执行的。
Redis 采用单线程(网络 I/O 和执行命令)还那么快,有如下几个原因:
- Redis 的大部分操作都在内存中完成,并且采用了高效的数据结构,因此性能瓶颈并非 CPU;
- Redis 采用单线程模型可以避免了多线程之间的竞争,省去了多线程切换带来的时间和性能上的开销,而且也不会导致死锁问题;
- Redis 采用了 I/O 多路复用机制处理大量的客户端 Socket 请求,IO 多路复用机制是指一个线程处理多个 IO 流,就是我们经常听到的 select/epoll 机制。简单来说,在 Redis 只运行单线程的情况下,该机制允许内核中,同时存在多个监听 Socket 和已连接 Socket。内核会一直监听这些 Socket 上的连接请求或数据请求。一旦有请求到达,就会交给 Redis 线程处理,这就实现了一个 Redis 线程处理多个 IO 流的效果。
CPU 并不是制约 Redis 性能表现的瓶颈所在,更多情况下是受到内存大小和网络I/O的限制,所以 Redis 使用单线程并没有什么问题。但是如果你想要使用服务器的多核 CPU,可以在一台服务器上启动多个节点或者采用切片集群的方式。
Redis 为什么要使用单线程模型?多线程不是可以提高性能吗?
多线程模式会面临执行顺序的不确定、共享资源的并发访问控制等问题,同时可能存在线程切换、加锁解锁和死锁的问题,需要额外的性能开销。而 Redis 主要的工作都是键值对的读写,所以单线程反而性能更高。且 Redis 的性能瓶颈主要在磁盘 IO 和网络 IO 方面,而多线程主要用于解决 CPU 的性能瓶颈。
后台线程
上文提到 Redis 的单线程是指网络 IO 和键值对读写由主线程完成,但是还有其他工作是交给子线程/进程来完成的。
Redis 在启动的时候,会启动后台线程(BIO):
- Redis 在 2.6 版本,会启动 2 个后台线程,分别处理关闭文件、AOF 刷盘这两个任务;
- Redis 在 4.0 版本之后,新增了一个新的后台线程,用来异步释放 Redis 内存,也就是 lazyfree 线程。例如执行 unlink key / flushdb async / flushall async 等命令,会把这些删除操作交给后台线程来执行,好处是不会导致 Redis 主线程卡顿。
当我们要删除大量数据的时候,不要使用 del 命令删除,因为 del 是在主线程处理的,会导致 Redis 主线程卡顿,应该使用 unlink 命令来异步删除。