Redis:单线程和多线程

目录

单线程和多线程

redis为什么快

单线程模型

多线程模型


单线程和多线程

redis有多个版本,分别使用了不同的线程策略:(大致情况,特殊版本除外)

  • redis4.0之前都是单纯的单线程。
  • redis4.0使用了多线程,就是单纯的加上了异步删除。
  • redis6.0及之后就是多线程,使用主线程进行命令处理,使用子线程进行多路I/O复用处理网络请求和进行命令解析。(注意,像持久化RDB、AOF、异步删除、集群数据同步等操作也是另起fork线程使用exec执行的)

redis为什么快

单线程模型

要考虑这个问题,就需要先理解单线程redis的工作流程:每个网络请求到达,redis都需要执行一次下述操作:

redis快就快在处理这个流程非常快:

  • I/O多路复用:使用了多路复用技术,单个线程即可接收多个socket请求。
  • 基于内存操作:Redis 的所有数据都存在内存中,因此所有的运算都是内存级别的,所以他的性能非常高。
  • 数据结构简单:Redis 的数据结构都很简单,其查询和操作的时间复杂度大多都是O(1)级别。
  • 无上下文切换:使用单线程模型就不用考虑上下文切换和多线程竞争的问题。

其他3个都很好理解,也不用太在意,那么为什么使用I/O多路复用就能很快地处理请求呢?

我们先看一下I/O多路复用的示意图:

可以看到,应用进程在使用epoll建立了监听队列之后,只需等待内核将准备好的文件描述符返回再进行处理即可,而Redis处理网络socket请求也是这个思路:

  1. 在启动Redis时,会创建一个事件循环(Event Loop)。这个事件循环是负责管理客户端连接的核心部分。
  2. 在事件循环启动后,Redis会将监听套接字添加到事件循环中,以便监控客户端连接请求。这样,Redis可以同时监听多个套接字,包括监听套接字和已建立的客户端套接字。
  3. 事件循环进入一个无限循环,不断地等待事件发生。这些事件可以包括新的客户端连接请求、已建立连接上的数据可读事件、已建立连接上的数据可写事件等。
  4. 当事件循环检测到某个事件发生时,它会调用相应的事件处理函数。对于新的客户端连接请求,事件处理函数会接受连接并将新套接字添加到事件循环。对于已建立连接上的数据可读事件,事件处理函数会读取客户端的命令请求。如果数据可写事件发生,表示可以向客户端发送响应。
  5. 执行客户端命令。(Redis会按照命令的顺序依次执行它们,确保命令的串行执行,而且Redis可以同时处理多个连接,而不会阻塞在某个特定连接上。)
  6. 当命令执行完成后,Redis会更新数据结构并将响应写入客户端套接字。如果客户端套接字不可写,Redis会将它加入待写队列,并在后续事件中继续尝试写入。
  7. 当Redis需要关闭客户端连接时,它将关闭客户端套接字并从事件循环中移除。

命令处理类比图:

有多个redis客户端时,也是这个流程,单线程redis使用I/O多路复用技术对多个socket描述符进行监听,每当有请求来时就让主线程进行处理;当有多个请求同时到达时,就排在epoll的监听队列中等待顺序处理。

使用该I/O多路复用模型后,redis主线程就一直处在接收命令——命令解析——命令执行——回写结果的循环中,而不会由于socket堵塞导致redis处在等待I/O的状态中(要等待socket传输完成后才触发事件),相比IO阻塞模型,这大大减少了IO阻塞时间,因此流程自然很快。

多线程模型

redis引入多线程是为了两个目的:

  1. 某些命令(如del大key)会导致服务卡顿,需要使用多线程异步删除。
  2. redis性能受CPU(执行命令的效率)、内存和网络IO(负责处理网络请求的效率)的影响。一般情况下,CPU和内存不会成为Redis的性能瓶颈。当CPU处理不过来底层网络硬件传递的网络请求时,就会导致网络I/O性能瓶颈,所以需要加快CPU处理网络请求的速度,因此需要使用多线程进行网络请求处理。

因此,在redis6.0之后,就使用多线程处理网络请求,使用单线程处理命令(单线程执行命令操作,就不用为了保证Lua脚本、事务的原子性,额外开发多线程互斥加锁机制了,这样一来,Redis线程模型实现就简单了):

引入多线程后处理网络请求的流程:

  1. 客户端与服务器建立连接,服务器获得socket,然后将socket分配给I/O线程,主线程这时就开始阻塞等待IO线程完成命令读取和解析。
  2. IO线程并行读取、解析客户端的命令。
  3. IO线程解析完后,就唤醒主线程进行执行命令。
  4. 主线程执行完后,将结果写入缓冲区,然后让IO线程回写执行结果到socket,自身就继续阻塞等待请求。

这样redis就抛弃了I/O多路复用模型,而是使用多线程模型解决网络IO问题,同时又使用单线程处理命令,保证了线程安全和高性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值