Redis 的高并发和快速原因
1.redis 是基于内存的,内存的读写速度非常快;
2.redis 是单线程的,省去了很多上下文切换线程的时间;
3.redis 使用多路复用技术,可以处理并发的连接。非阻塞 IO 内部实现采用 epoll,采用了 epoll + 自己实现的简单的事件框架。epoll 中的读、写、关闭、连接都转化成了事件,然后利用 epoll 的多路复用特性,绝不在 io 上浪费一点时间。
下面重点介绍单线程设计和 IO 多路复用核心设计快的原因。
为什么 Redis 是单线程的
1. 官方答案
因为 Redis 是基于内存的操作,CPU 不是 Redis 的瓶颈,Redis 的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且 CPU 不会成为瓶颈,那就顺理成章地采用单线程的方案了。
2. 性能指标
关于 redis 的性能,官方网站也有,普通笔记本轻松处理每秒几十万的请求。
3. 详细原因
1)不需要各种锁的性能消耗
Redis 的数据结构并不全是简单的 Key-Value,还有 list,hash 等复杂的结构,这些结构有可能会进行很细粒度的操作,比如在很长的列表后面添加一个元素,在 hash 当中添加或者删除
一个对象。这些操作可能就需要加非常多的锁,导致的结果是同步开销大大增加。
总之,在单线程的情况下,就不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗。
2)单线程多进程集群方案
单线程的威力实际上非常强大,每核心效率也非常高,多线程自然是可以比单线程有更高的性能上限,但是在今天的计算环境中,即使是单机多线程的上限也往往不能满足需要了,需要进一步摸索的是多服务器集群化的方案,这些方案中多线程的技术照样是用不上的。
进程和线程都是操作系统中的并发执行的单位,但是它们有着不同的特点。进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位。一个进程可以包含多个线程,但至少有一个线程。线程是程序执行流的最小单元,是系统独立调度和分配CPU(独立运行)的基本单位。进程之间相互独立,而同一进程下的各个线程之间共享程序的内存空间(包括代码段、数据集、堆等)。¹²³
希望这能回答您的问题。如果您还有其他问题,请随时问我。
所以单线程、多进程的集群不失为一个时髦的解决方案。
3)CPU 消耗
采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU。
但是如果 CPU 成为 Redis 瓶颈,或者不想让服务器其他 CUP 核闲置,那怎么办?
可以考虑多起几个 Redis 进程,Redis 是 key-value 数据库,不是关系数据库,数据之间没有约束。只要客户端分清哪些 key 放在哪个 Redis 进程上就可以了。
Redis 单线程的优劣势
1. 单进程单线程优势
- 代码更清晰,处理逻辑更简单
- 不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗
- 不存在多进程或者多线程导致的切换而消耗 CPU
2. 单进程单线程弊端
- 无法发挥多核 CPU 性能,不过可以通过在单机开多个 Redis 实例来完善;
IO 多路复用技术
redis 采用网络 IO 多路复用技术来保证在多连接的时候, 系统的高吞吐量。
多路 - 指的是多个 socket 连接,复用 - 指的是复用一个线程。多路复用主要有三种技术:select,poll,epoll。epoll 是最新的也是目前最好的多路复用技术。
这里 “多路” 指的是多个网络连接,“复用”指的是复用同一个线程。采用多路I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 IO 的时间消耗),且 Redis 在内存中操作数据的速度非常快(内存内的操作不会成为这里的性能瓶颈),主要以上两点造就了 Redis 具有很高的吞吐量。
Redis 高并发快总结
-
Redis 是纯内存数据库,一般都是简单的存取操作,线程占用的时间很多,时间的花费主要集中在 IO 上,所以读取速度快。
-
再说一下 IO,Redis 使用的是非阻塞 IO,IO 多路复用,使用了单线程来轮询描述符,将数据库的开、关、读、写都转换成了事件,减少了线程切换时上下文的切换和竞争。
-
Redis 采用了单线程的模型,保证了每个操作的原子性,也减少了线程的上下文切换和竞争。
-
另外,数据结构也帮了不少忙,Redis 全程使用 hash 结构,读取速度快,还有一些特殊的数据结构,对数据存储进行了优化,如压缩表,对短数据进行压缩存储,再如,跳表,使用有序的数据结构加快读取的速度。
-
还有一点,Redis 采用自己实现的事件分离器,效率比较高,内部采用非阻塞的执行方式,吞吐能力比较大。