【redis】redis的单线程模型为什么效率高?
文章目录
- 单线程模型
- 单线程的 Redis 为什么效率高?速度快?
- IO多路复用
- epoll
单线程模型
Redis 只使用一个线程,处理所有的命令请求。不是说一个 Redis 服务器进程内部只有一个线程,其实也有多个线程,多个线程是在处理网络IO
假设有多个客户端,要同时操作 Redis
服务器
incr
是increase
,作用是把key
的value
进行+1
操作
[!quote] 线程安全问题
- 在多线程中,针对类似这样的场景,两个线程尝试同时对一个变量进行自增,表面上看是自增两次,实际上可能只自增了一次
当前这两个客户端,也相当于“并发”的发起了上述的请求,此时是否就意味着服务器这边也会存在类似的线程安全问题呢?
- 幸运的是,并不会。
Redis
服务器实际上是单线程模型,保证了当前收到的这多个请求是串行执行的 - 虽然请求发过来是并发的,但是到了服务器上就会排队,按序执行
Redis
能够使用单线程模型很好的工作,主要原因在于 Redis
的核心业务逻辑,都是短平快的,不太消耗 CPU
资源,也就不太吃多核了
弊端:
Redis
必须要特别小心,某个操作占用时间长,就会阻塞其他命令的执行(前面的keys *
)
单线程的 Redis 为什么效率高?速度快?
#高频面试
Redis
虽然是单线程模型,但是为什么效率这么高,速度这么快呢?
- 首先要明确,“快”的参照物是数据库(MySQL,Oracle,SQL server)
Redis
的操作访问内存;数据库是访问硬盘Redis
核心功能,比数据库的核心功能更简单- 数据库对于数据的插入删除查询… 都有更复杂的功能支持,这样的功能势必要花费更多的开销。
- 比如,针对插入删除,数据库中的各种约束,都会使数据库做额外的工作(分组,联合查询…)
- 单线程模型,避免了一些不必要的线程竞争开销
Redis
每个基本操作都是短平快,就是简单操作一下内存数据,不是什么特别消耗 CPU 的操作,就算搞多个线程,提升也不大
- 处理网络 IO 的时候,使用了
epoll
这样的 IO多路复用
IO多路复用
本质上是让我们一个线程,管理多个 socket
针对 TCP
来说,服务器这边每次要服务一个客户端,都需要给这个客户端安排一个 socket
,通过这个 socket
来和客户端进行通信
一个服务器要服务多个客户端,同时就有很多个 socket
。这些 socket 上都是无时无刻都在传输数据吗?还是大部分时间都是闲置的?
- 很多情况下,每个客户端和服务器之间的通信也没那么频繁。此时这么多
socket
大部分时间都是静默的,上面是没有数据需要传输的。 - 同一时刻,只有少数
socket
是活跃的,这就是我们使用 IO复用的重大前提
最开始介绍 TCP 服务器的时候,有一个版本就是每个客户端都分配一个线程==>客户端多了,线程就多了,系统开销就大了
基于上述的这些原因,就搞了“IO多路复用”,一个线程来处理多个 socket
- 操作系统,给程序员提供的机制,提供了一套 API,内部的功能都是操作系统内核实现的
Linux
上提供的 IO多路复用,主要是三套 API:select
、poll
、epoll
epoll
比如你今晚,你想吃烧烤,你妈想吃饺子,你爸想吃炒菜
- 你自己去买,先买烧烤,等;再买饺子,等;再买炒菜,等;完成。——>单线程,花的时间是最多的
- 你们三个一起去买,各买各的,分别等;完成——>多线程,花的时间机会缩短很多,等待的时间是三者最大值,系统开销也会更大
- 你自己去买,你先去买烧烤,给老板说“好了叫我”;再去买饺子,给老板说“好了叫我”;再去买炒菜,给老板说“好了叫我”,此时一个线程同时等待三份饭——>IO 多路复用的方案,此时等待的时间相比于多线程方案,相差不大,但是只需要一个线程就可以了
- 最关键的就是老爸能够喊我,哪个客户端来数据了,操作系统就能通知到应用程序
- 服务器开发中最主流的方案,尤其是 IO路复用中的
epoll
epoll
相当于时间通知/回调机制
select
是你自己再几个摊位之间不停地问,没人提醒你
如果这三件事都是交互特别频繁的,还是老老实实多搞几个线程靠谱,一个线程容易忙不过来
C++
可以直接使用 Linux 原生的epoll
API
Java
可以使用NIO
(标准库提供的一组类,底层就是封装了epoll
)