前言
Redis 使⽤了单线程架构来实现⾼性能的内存数据库服务,本文章将会分析 Redis 单线程命令处理机制,接着分析 Redis 单线程模型为什么性能如此之⾼
Redis 单线程命令处理机制
假设现在我们有 3 个客户端,同时向 Redis 服务器发送请求,在宏观上看三个客户端是同时要求 Redis 去执行命令的
但微观⻆度,这些命令在 Redis 中还是采⽤线性⽅式去执⾏的,只是原则上命令的执⾏顺序是不确定的,但⼀定不会有两条命令被同步执⾏,因为 Redis 内部只有一个线程,一次只能执行一条命令
为什么单线程还能这么快
通常来讲,单线程处理能⼒要⽐多线程差,例如有 10000 公⽄货物,每辆⻋的运载能⼒是每次 200 公⽄,那么要 50 次才能完成;但是如果有 50 辆⻋,只要安排合理,只需要一次就可以完成任务。那么为什么 Redis 使⽤单线程模型会达到每秒万级别的处理能⼒呢?
可以将其归结为以下几点:
a. 纯内存访问。Redis 将所有数据放在内存中,内存的响应时⻓⼤约为 100 纳秒,时间非常短,这是Redis 达到每秒万级别访问的重要基础。
b. 核心功能简单。相比于数据库来说,数据库对于数据的各种操作都有复杂的功能支持,这些功能势必会造成较大的开销,而 redis 提供的功能就少了许多,所以效率也高了许多
c.单线程模型。避免了一些不必要的线程竞争开销,redis 的每个基本操作都是短平快的,就是简单操作一下内存数据,不是很消耗 cpu 资源,所以用多线程得到的提升不大。(使用多线程的前提是,命令会消耗较多的 cpu 资源,引入多线程就可以引入更多的 cpu 资源提高效率)
d.处理网络 IO 时,使用了 epoll 这样的 IO 多路复用机制。
IO 多路复用机制
IO 多路复用机制的核心就是:一个线程可以同时管理多个 socket(针对 TCP 来说,服务器这边每次要服务一个客户端,都需要给这个客户端安排一个socket )相当于同时管理多个客户端,处理多个客户端传来的请求
有同学可能会说:客户端不是无时无刻的都在传输数据吗,一个线程怎么会忙得过来呢?但实际上大多数情况下,客户端和服务器之间的通信没有那么频繁,所以同一时刻只有少部分的客户端需要传输数据
并且 epoll 具有事件通知机制,当客户端传输数据到线程中时,会通知线程来处理,这样线程就不需要一直遍历客户端,判断是否有命令需要处理,直接等待通知去处理请求即可
但如果客户端确实无时无刻的都在传输数据,那么 IO 多路复用机制意义就不大了,还是老老实实多搞几个线程比较好
使用单线程的缺点
虽然单线程给 Redis 带来很多好处,但还是有⼀个致命的问题:对于单个命令的执⾏时间都是有要求的。如果某个命令执⾏过⻓,会导致其他命令全部处于等待队列中,迟迟等不到响应,造成客户端的阻塞,对于 Redis 这种⾼性能的服务来说是⾮常严重的,所以 Redis 是⾯向快速执⾏场景的数据库。