Redis -- IO多路复用及redis6的多线程

news2024/11/23 21:55:48

都知道redis是通过单线程+io多路复用来避免并发问题的,然后在redis6的时候redis引入了多线程,这里就来详细说说IO多路复用模型以及redis的多线程。

Redis 的 I/O 多路复用模型有效的解决单线程的服务端,使用不阻塞方式处理多个 client 端请求问题。在看 I/O 多路复用知识之前,我们先来看看 Redis 的客服端怎么跟客服端建立连接的、单线程 socket 服务端为什么会存在 I/O 阻塞。

1. Redis客户端连接

Redis 通过监听一个 TCP 端口或者 Unix socket 的方式来接收来自 client 端的连接,当一个连接建立后,Redis 内部会进行以下一些操作:

  1. 首先,客户端 socket 会被设置为非阻塞模式,因为 Redis 在网络事件处理上采用的是非阻塞多路复用模型。
  2. 然后为这个 socket 设置 TCP_NODELAY 属性,禁用 Nagle 算法。
  3. 然后创建一个可读的文件事件用于监听这个客户端 socket 的数据发送。

2. 阻塞I/O

在 socket 连接中,一个服务器进程和一个客户端进行通信时,当一个 client 端向服务端写数据时,如果 client 端没有发送数据,那么服务端的 read 将一直阻塞,直到客户端 write 发来数据。在一个客户和服务器通信时没什么问题,当多个客户 与 一个服务器通信时,就存在问题了。如下图,两个客服端同时连接一个服务端进行写数据的时序图。
在这里插入图片描述

从上图可以看出一个服务器进程和多个客户端进程通信的问题:

  1. client1 和服务端建立连接后,服务端会一直阻塞于 client1,直到 client1 客户端 write 发来数据才开始后面的操作。服务端阻塞期间,即使其他客服端 client2 的数据提前到来,也不能处理 client2 客服端的请求。
  2. 有一个严重的问题就是,如果客户端 client1 一直没有 write 数据到来,那么服务端 service 会一直阻塞,不能处理其他客户的服务。

上面就是 Redis 通过 Unix socket 的方式来接收来自 client 端的连接存在的 I/O 阻塞问题,而 「I/O 多路复用」就是为了解决服务端一直阻塞等待某一个 client 的数据到来,即使其他client的数据提前到来,也不会被处理的问题。

3. I/O多路复用

为什么 Redis 中要使用 I/O 多路复用这种技术呢?因为 Redis 是跑在「单线程」中的,所有的操作都是按照顺序线性执行的,但是「由于读写操作等待用户输入 或 输出都是阻塞的」,所以 I/O 操作在一般情况下往往不能直接返回,这会导致某一文件的 I/O 阻塞导致整个进程无法对其它客户提供服务。而 I/O 多路复用就是为了解决这个问题而出现的。「为了让单线程(进程)的服务端应用同时处理多个客户端的事件,Redis 采用了 IO 多路复用机制。」

这里多路指的是多个网络连接客户端】;复用指的是复用同一个线程(单进程)】;

I/O 多路复用:其实是使用一个线程来检查多个 Socket 的就绪状态,在单个线程中通过记录跟踪每一个 socket(I/O流)的状态来管理处理多个 I/O 流

如下图是 Redis 的 I/O 多路复用模型:
在这里插入图片描述

其中:FD即:文件描述符(file descriptor):
Linux 系统中,把一切都看做是文件,当进程打开现有文件或创建新文件时,内核向进程返回一个文件描述符。可以理解文件描述符是一个索引,这样,要操作文件的时候,我们直接找到索引就可以对其进行操作了。我们将这个索引叫做文件描述符(file descriptor),简称fd。

如上图对 Redis 的 I/O 多路复用模型进行一下描述说明:

  1. 一个 socket 客户端与服务端连接时,会生成对应一个套接字描述符(套接字描述符是文件描述符的一种),每一个 socket 网络连接其实都对应一个文件描述符。

  2. 多个客户端与服务端连接时,Redis 使用 「I/O 多路复用程序」 将客户端 socket 对应的 FD 注册到监听列表(一个队列)中。当客服端执行 read、write 等操作命令时,I/O 多路复用程序会将命令封装成一个事件,并绑定到对应的 FD 上。

  3. 文件事件处理器」使用 I/O 多路复用模块同时监控多个文件描述符(fd)的读写情况,当 accept、read、write 和 close 文件事件产生时,文件事件处理器就会回调 FD 绑定的事件处理器进行处理相关命令操作。

  4. 文件事件分派器接收到I/O多路复用程序传来的套接字fd后,并根据套接字产生的事件类型,将套接字派发给相应的事件处理器来进行处理相关命令操作。

    • 例如:以Redis的I/O多路复用程序 epoll函数为例
      多个客户端连接服务端时,Redis会将客户端socket对应的fd注册进epoll,然后epoll同时监听多个文件描述符(FD)是否有数据到来,如果有数据来了就通知事件处理器赶紧处理,这样就不会存在服务端一直等待某个客户端给数据的情形。
    • I/O多路复用程序函数有select、poll、epoll、kqueue
  5. 整个文件事件处理器是在单线程上运行的,但是通过 I/O 多路复用模块的引入,实现了同时对多个 FD 读写的监控,当其中一个 client 端达到写或读的状态,文件事件处理器就马上执行,从而就不会出现 I/O 堵塞的问题,提高了网络通信的性能。

  6. 如上图,Redis 的 I/O 多路复用模式使用的是 「Reactor 设计模式」的方式来实现。

3.1 IO多路复用总结:

  • Redis 的 I/O 多路复用程序函数有 select、poll、epoll、kqueue。select 作为备选方案,由于其在使用时会扫描全部监听的文件描述符,并且只能同时服务 1024 个文件描述符,所以是备选方案。
  • I/O 多路复用模型是利用 select、poll、epoll 函数可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉。当有一个或多个流有 I/O 事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll 是只轮询那些真正发出了事件的流),依次顺序的处理就绪的流,这种做法就避免了大量无用的等待操作

4. Redis6新引入的多线程

4.1 先说说之前的单线程优缺点:

对于一个请求操作, Redis 主要做 3 件事情: 从客户端读取数据、执行 Redis 命令、回写数据给客户端(如果再准确点, 其实还包括对协议的解析)。所以主线程其实就是把所有操作的这 3 件事情, 串行一起执行, 因为是基于内存, 所以执行速度非常快:

优点 VS 缺点:

  • 优势: a. 不存在锁的问题 b. 避免线程间 CPU 切换
  • 缺点: a. 单线程无法利用多 CPUb. 串行操作, 某个操作"出问题"会"阻塞"后续操作

4.2 redis的多线程

Redis 多线程的优化思路:
因为网络 I/O 在 Redis 执行期间占用了大部分 CPU 时间, 所以把网络 I/O 部分单独抽离出来, 做成多线程的方式。这里所说的多线程, 其实就是将 Redis 单线程中做的这两件事情"从客户端读取数据、回写数据给客户端"(也可以称为网络 I/O), 处理成多线程的方式, 但是"执行 Redis 命令"还是在主线程中串行执行, 这个逻辑保持不变。

可能有同学会问, 主线程和多个 I/O 线程, 都同时处理图中的"队列", 是不是会存在锁竞争的关系呢? 这里有个巧妙的设计, 就是当 epoll 获取 socket 链接时, 会将该事件先全部扔进队列中, 比如扔了 N 个事件, 这时主线程就会处于忙等 (spinlock 自旋锁的效果)状态。然后多个 I/O 线程开始去并行进行网络 I/O, 并对数据进行协议解析, 当队列全部处理完毕后, 主线程会对队列中请求串行"执行 Redis 命令", 然后清空该队列。所以整个执行流程总结下来: 主线程执行请求入队列 -> I/O 线程并行进行网络读 -> 主线程串行执行 Redis 命令 -> I/O 线程并行进行网络写 -> 主线程清空队列, 并接收下一批请求。

优点 VS 缺点

  • 优点: a. 提高响应速度, 充分使用 CPU
  • 缺点: a. 增加了代码复杂性

4.3 总结

  • 5.0 版本及以前, 处理客户端请求的线程只有一个, 串行处理;
  • 6.0 版本引入了 worker Thread, 只处理网络 IO 读取和写入, 核心 IO 负责串行处理客户端指令。

4.4 关于redis的多线程详解可以看:

https://www.51cto.com/article/713253.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/158289.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

optional妙用解决NullPointerException

背景 作为一个java程序员,我们在日常开发中经常会碰到一个臭名昭著空异常,所有程序员都经历过的痛点,空指针异常(NullPointerException) java8中出现的Optional是java开始迈向函数式编程的一大步,也有效的…

实验 4 图像复原与重建

目录一、实验目的二、实验例题1. 噪声模型2. 只存在噪声的滤波——空间滤波3. 退化函数建模4. 存在线性退化和噪声的滤波(1) 逆滤波(2) 最小均方误差(维纳)滤波附录一、实验目的 了解一些常用随机噪声的生成方法。掌握根据指定退化函数对图像进行退化的方法。掌握当模糊图像只…

十一、Gtk4-Instance Initialization and destruction

文本文件编辑器(tfe)的新版本将在本节和以下四节中编写。它是tfe5。与之前的版本相比,有很多变化。它们位于两个目录中,src/tfe5和src/tfetextview。 1 封装 我们将C源文件分为两部分。但就封装而言,这还不够。 tfe.c包含除Tfe TextView之…

【Linux】线程控制

目录🌈前言🌸1、Linux线程控制🍡1.1、创建线程(pthread_create)🍢1.2、通过指令查看线程PID和LWP🍧1.3、获取线程ID(pthread_self)🍨1.4、线程终止(pthread_exit/cancel)🍨1.5、线程等待(pthrea…

一文读懂PCB阻焊工艺

PCB阻焊油墨根据固化方式,阻焊油墨有感光显影型的油墨,有热固化的热固油墨,还有UV光固化的UV油墨。而根据板材分类,又有PCB硬板阻焊油墨,FPC软板阻焊油墨,还有铝基板阻焊油墨,铝基板油墨也可以用…

力扣算法(Java实现)—数组入门(11题)

文章目录1.删除排序数组中的重复项2.买卖股票的最佳时机 II3.旋转数组4.存在重复元素5.找出只出现一次的元素6.两个数组的交集7.移动零8.加一9.两数之和10.有效的数独11.旋转图像💎💎💎💎💎 更多资源链接,欢…

【手写 Vue2.x 源码】第十八篇 - 根据 render 函数,生成 vnode

一,前言 上篇,介绍了render 函数的生成,主要涉及以下两点: 使用 with 对生成的 code 进行一次包装将包装后的完整 code 字符串,通过 new Function 输出为 render 函数 本篇,根据 render 函数&#xff0c…

linux系统中QT里面的视频播放器的实现方法

大家好,今天主要和大家聊一聊,如何使用QT中视频播放器的方法。 目录 第一:视频播放器基本简介 第二:视频播放器头文件说明 第三:源文件的具体实现方法 第四:运行效果显示 第一:视频播放器基本…

ADS振铃仿真

目录 无振铃时的原理图 无振铃时的Vout和VL输出波形 ​LineCalc对微带线阻抗的计算结果 将微带线线宽Width统一由116改为130 将微带线线宽Width统一由116改为80 将微带线TL9线宽由116改为300 将微带线TL9线宽由116改为50 本文介绍了微带线线宽变化时100MHz信号的反射现象…

2023 年 15 大测试自动化趋势

在过去,软件测试只是为了发现软件产品中的错误。目标是——提高软件质量。但如今,软件测试的范围已经扩大。在软件测试方面,自动化测试一直走在前列。按照最新的测试自动化趋势,软件测试行业有望比过去十年发展得更快。 根据 Mar…

Java面向对象综合训练

Java面向对象综合训练一、文字版格斗游戏Role类测试类输出结果二、对象数组练习对象数组1商品类测试类输出结果对象数组2汽车类测试类输出结果对象数组3手机类测试类输出结果对象数组4女朋友类测试类输出结果对象数组5学生类测试类输出结果一、文字版格斗游戏 Role类 import j…

去掉 域名后面的 /#/ vue-router 和 hbuilder发布 web项目和h5项目

1. vue-router vue-router默认的路由模式是hash,我们要去掉url中的#需要将路由模式切换为history const router new VueRouter({base: test, // 如果项目项目在 域名 根目录下,则去掉这行mode: history, // 路由模式... })这样子,url中的#…

为什么ERP和项目管理的集成是必要的?

在一个企业中,传统的责任分工意味着会计人员看管资金和维持财务标准,而职能经理分配人力资源和维持技术标准。项目经理指导分配的资金和其他资源,同时努力实现项目目标。每个学科都有自己的业务规则,自己的做法,自己的…

C++ | 左值、右值、将亡值和引用的概念 | 聊聊我对它们的深入理解

文章目录前言左右值的辨析一个特殊的问题将亡值引用的深刻理解前言 这篇文章是我在探究完美转发这个语法点时,引发的相关问题思考,为了使自己的理解更深刻,故写下这篇博客 左右值的辨析 首先需要明白两个概念:类型(…

1577_AURIX_TC275_MTU中检测控制相关寄存器

全部学习汇总: GreyZhang/g_TC275: happy hacking for TC275! (github.com) 开篇介绍的功能室之前看过很多次的一个握手的功能。快速行以及快速列模式的测试中,这个行列其实是对应的存储的bit阵列信息。一个对应相应的字,另一个则对应bit序列…

【Linux】进程创建、终止、等待、替换、shell派生子进程的理解…

柴犬: 你好啊,屏幕前的大帅哥or大美女,和我一起享受美好的今天叭😃😃😃 文章目录一、进程创建1.调用fork之后,内核都做了什么?2.如何理解fork函数有两个返回值?3.如何理…

(短信服务)java SpringBoot 阿里云短信功能实现发送手机验证码

一.阿里云准备工作 1.阿里云短信服务-注册账号 阿里云官网: https://www.aliyun.com/ 点击官网首页注册按钮。 2.阿里云短信服务-设置短信签名(阿里云提供测试的签名,暂时可以跳过) 注册成功后,点击登录按钮进行登录。登录后…

简单方式调用WebService服务

好久没有进行过WebService开发了,由于项目需要,重拾WebService,记录一下简单的服务调用方法。拿到需求,仅半页word,其他的就没有了,为了快速开发,尝试过使用插件逆向生成调用的一大堆类&#xf…

AWVS安装与激活

AWVS安装与激活 1.AWVS简介 AWVS(Acunetix Web Vulnerability Scanner)是一款知名的网络漏洞扫描工具,通过网络爬虫测试网站安全,检测流行的Web应用攻击,如跨站脚本、sql 注入等。据统计,75% 的互联网攻击…

pmp备考全攻略

我这里分享一下我备考的经验,如何对大家有帮助也可以稍微给点支持,让更多人了解! 一,我的pmp备考经验 1.一阶段:铺底,花费时间1.5周左右 主要是熟悉考试框架和内容,通过看网盘资料里的章节重…