当前位置: 首页 > news >正文

Redis线程模型

        前面的文章介绍了Redis的底层数据结构,这篇文章来介绍一下Redis的线程模型。

Redis为什么选择单线程?

        官方的回答是这样的,对于Redis来说,CPU通常不会成为瓶颈,因为大多数的请求不会是CPU密集型的,而是IO密集型的。如果不考虑RDB、AOF等信息持久化方案的话,Redis是完全纯内存操作,纯内存操作的执行速度是非常快的,所以这部分操作不会成为Redis的性能瓶颈。真正影响Redis性能的,是网络IO,也就是客户端和服务端之间的网络延迟造成的。因此Redis采用了单线程,在网络IO部分采用IO多路复用。

        更加具体的原因是在CPU不是性能瓶颈的前提下,相对于多线程模型,单线程模型避免了频繁上下文切换造成的开销,同时也不用考虑Redis众多底层数据结构的并发安全问题,这也使得Redis的底层相对简单好维护。总的来说,Redis采用单线程可以在保持高性能的同时,保持代码的简单可维护,毕竟多线程的理论和实际对比就可以很好的说明多线程在使用时的复杂与难以维护:

Redis为什么又引入了多线程?

        Redis其实在v4.0时就引入了多线程,主要用来异步处理一些比较耗时的任务,避免核心线程被长时间阻塞;v6.0时引入了多线程IO,主要用来处理网络数据的读写和协议内容的解析。多线程IO的引入主要是由于互联网的飞速发展,互联网业务需要处理的线上流量越来越大,Redis的单线程模式会导致相当一部分CPU时间消耗在网络IO上,而导致Redis整体的吞吐量降低。如果要对Redis性能进行优化,可以从两方面来入手:①优化网络IO模块、②提高机器内存的读写速度。

        第②种依赖于硬件的突破,所以只能从第一种方法入手,第一种方法又可以细分为两个方向:①零拷贝技术或者DPDK技术、②利用多核CPU优势。

        零拷贝技术有自身的局限性,无法完全适配Redis这一类复杂的网络IO场景。DPDK技术通过旁路网卡IO绕过内核协议的方式又太过于复杂以及需要内核的支持。所以最终选择的就是利用多核CPU的优势,通过使用多线程将网络IO任务进行分摊。

        Redis6.0在引入多线程IO后,在4线程IO时,GET/SET的性能相较于单线程几乎翻倍。

Redis的线程模型

        Redis的线程模型分为v6.0之前和v6.0之后两个版本。

v6.0之前:

        采用基于Recator模式的网络事件处理器。这个处理器被称为文件事件处理器。它的组成结构为4部分,多个Socket、IO多路复用程序、文件事件分派器和事件处理器。因为文件事件分派器队列和消费是单线程的,所以说Redis是单线程模型。Redis6.0之前的线程模型如下图所示:

        多个Socket:Socket会产生AE_READABLE和AE_WRITABLE事件。当Socket变得可读或者有新的可以应答的Socket出现时,就会产生一个AE_READABLE事件;当Socket变得可写时,就会产生一个AE_WRITABLE事件。

        IO多路复用程序:IO多路复用的实现有select、poll和epoll三种技术,其中epoll是性能最好的。

        事件处理器:事件处理器包括连接应答处理器、命令请求处理器和命令回复处理器。如果是客户端请求连接Redis,那么会为Socket关联连接应答处理器;如果是客户端要写数据到Redis,那么会为Socket关联命令请求处理器;如果是客户端要从Redis读数据,那么会为Socket关联命令回复处理器。

        多个Socket会产生不同的事件,不同的事件对应着不同的操作,IO多路复用程序监听着这些Socket,当这些Socket产生了事件,IO多路复用程序会将这些事件放到一个队列中,通过这个队列,以有序、同步、每次一个事件的方式向文件事件分派器中传送。当事件处理器处理完一个事件后,IO多路复用程序才会继续向文件分派处理器传送下一个事件。

        Redisv6.0线程模型下,客户端与Redis一次完整的通信流程如下:

        ①Redis启动初始化时,Redis会将连接应答处理器与AE_READABLE事件关联起来。

        ②一个客户端发起与Redis的连接请求,此时Redis产生一个AE_READABLE事件,此时连接应答处理器来处理此事件,连接应答处理器与客户端建立连接,创建客户端相应的Socket,同时将这个Socket的AE_READABLE事件与命令请求处理器关联。

        ③这个客户端向Redis发送了一条命令,相应的Socket产生一个AE_READABLE事件,IO多路复用程序将事件压入队列中。事件分配处理器拿到该事件,将该事件分配给命令请求处理器处理,命令请求处理器读取事件中的命令并完成。完成后将Socket的AE_WRITABLE事件与命令回复处理器相关联。

        ④如果客户端已经准备好接收数据,相应Socket会产生一个AE_WRITABLE事件,同时会压入队列中然后被事件分配处理器分配给命令回复处理器,由其将准备好的响应数据写入Socket给客户端读取。

        ⑤命令回复处理器写完后,就会删除该Socket的AE_WRITABLE事件与命令请求处理器的关联关系。

v6.0之后:

        v6.0之后的流程与v6.0之前的最大区别在于网络数据的读写部分。

        Redis的主线程负责接受连接建立请求,获取Socket并将其放入全局等待读处理队列;主线程处理完读事件后,通过Round Robin将这些链接分配给IO线程;主线程阻塞等待IO线程读取Socket完成;主线程通过单线程的方式执行请求命令,并将数据写入缓冲区;主线程阻塞等待IO线程将数据写回给Socket。具体流程如下图所示:

        可以看到,Redis的多线程只体现在Socket命令的读取和写回,而命令的执行还是主线程在单线程执行,所以说Redis的核心仍然是单线程的,不用考虑并发安全的问题。

        到此Redis的线程模型就介绍完毕啦,大家有什么问题或者勘误可以在评论区留言,笔者看到都会回复的。

        

相关文章:

  • Gitee Wiki:重塑关键领域软件研发的知识管理范式
  • 时代星光推出战狼W60智能运载无人机,主要性能超市场同类产品一倍!
  • 登录vmware vcenter报vSphere Client service has stopped working错误
  • 最佳实践 | 璞华易研“PLM+AI智能研发平台”,助力汉旸科技实现高新材料“数据驱动研发”
  • 实验设计与分析(第6版,Montgomery著,傅珏生译) 第9章三水平和混合水平析因设计与分式析因设计9.5节思考题9.1 R语言解题
  • 从0开始学习R语言--Day16--倾向得分匹配
  • 实验设计与分析(第6版,Montgomery著,傅珏生译) 第10章拟合回归模型10.9节思考题10.12 R语言解题
  • Vue.js教学第十八章:Vue 与后端交互(二):Axios 拦截器与高级应用
  • TypeScript 高级类型深度指南:从类型体操到实战设计
  • 仓颉项目调试配置与多文件场景下的问题解析
  • Leetcode - 周赛 452
  • ARM GIC V3概述
  • 工作自动化——工作自动提炼--智能编程——仙盟创梦IDE
  • 2024-2025-2-《移动机器人设计与实践》-复习资料-1-7
  • redis数据过期策略
  • 《对象创建的秘密:Java 内存布局、逃逸分析与 TLAB 优化详解》
  • C# winform教程(二)----button
  • Hadoop HDFS 体系结构与文件读写流程剖析
  • Matlab实现LSTM-SVM回归预测,作者:机器学习之心
  • Java并发编程:读写锁与普通互斥锁的深度对比
  • 一个主机一个域名做网站/seo技巧是什么意思
  • 网站开发文档撰写模板/企业网站设计思路
  • 普陀网站建设/sem账户托管公司
  • 软件下载网站建设/优化设计七年级上册数学答案
  • 济南网站的公司哪家好/百度公司简介
  • 营销网站主题有哪些/网站联盟营销