【Redis知识点总结】(二)——Redis高性能IO模型剖析

Redis知识点总结(二)——Redis高性能IO模型及其事件驱动框架剖析

  • IO多路复用
    • 传统的阻塞式IO
    • 同步非阻塞IO
    • IO多路复用机制
  • Redis的IO模型
  • Redis的事件驱动框架

IO多路复用

Redis的高性能的秘密,在于它底层使用了IO多路复用这种高性能的网络IO,IO多路复用是一种高性能的IO机制。

传统的阻塞式IO

传统的同步阻塞式IO,一个IO连接对应一个线程,也就是说一个线程只能监听一个IO连接,并且在没有数据到达前,这个线程会阻塞等待数据的到达,在数据到达后,才把数据读取到应用程序的内存区域。

比如我们熟悉的socket编程,就是典型的同步阻塞式网络IO,ServerSocket的accept()方法监听指定端口接收客户端建立连接,此时当前线程会阻塞,等待客户端发起连接。建立连接后返回一个Socket表示与客户端建立了一个连接,然后我们创建一个线程Thread,在线程中调用Socket的read()方法,等待客户端发送数据,如果客户端迟迟不发送数据,那么该线程将会一直被阻塞

在这里插入图片描述

这是一种性能比较低的IO机制,原因在于一个线程只能监听一个连接,并且在数据没有到达之前,需要阻塞等待。

同步非阻塞IO

而同步非阻塞式IO则不一样,它可以尝试性的读取看看是否有数据,如果没有数据可以立即返回,不会阻塞,当前线程可以去干点别的事情,然后再次回来尝试读取,如果发现有数据到达,才会阻塞当前线程,当前线程会把数据读取到应用程序用户空间。

在这里插入图片描述

在没有数据达到前,当前线程不会阻塞,因此叫非阻塞式IO,而有数据达到时,数据读取的工作是当前线程自己处理的(异步IO不需要线程自己读取数据),因此又叫同步IO,合在一起就是同步非阻塞IO。

这种IO机制虽然不会阻塞当前线程,但是不停尝试读取的做法非常消耗CPU资源,于是就有了IO多路复用。

IO多路复用机制

IO多路复用最大的特点就是一个线程可以监听多个socket。在Linux操作系统里面,提供了select、poll、epoll三种IO多路复用API,由于Redis底层使用的时epoll,我们就分析一下epoll这种IO多路复用机制。

epoll这种IO多路复用机制有三个函数,分别是epoll_create、epoll_ctl、epoll_wait。epoll_create的作用是创建一个epoll实例,这个epoll实例是一个IO多路复用器,里面使用一个红黑树结构存储注册进来的socket文件描述符,当某个socket有数据到达或有连接需要建立时,又会把该socket复制到一个链表结构当中;epoll_ctl则是把一个socket文件描述符注册到epoll实例当中;epoll_wait则是获取epoll实例中已经有事件就绪的socket,也就是epoll实例中的链表,把该链表拷贝到用户空间,当前线程就可以遍历该链表进行处理。

在这里插入图片描述

如果是建立连接事件,则调用socket的accept()函数建立连接获取另一个socket,把该socket注册到epoll实例中,如果是有数据达到,则调用socket的read()函数读取数据,如果是有数据需要写出,则调用socket的write()函数。

在这里插入图片描述

Redis的IO模型

redis基于IO多路复用进行封装,就有了自己的IO模型。Redis的IO模型是单线程Reactor模型,也就是事件监听(reactor)、建立建立连接(acceptor)、事件处理(handler),都由同一个线程负责。这里的reactor、acceptor、handler是IO模型中的三种角色,三个角色可以由不同线程担当,也可由同一个线程担当,在单线程Reactor这种IO模型中,显然三种角色都是由同一个线程担当。此时reactor表示事件监听的处理逻辑,acceptor表示连接建立的处理逻辑,handler表示处理读写事件的逻辑。

在这里插入图片描述

在单线程reactor这种IO模型下,程序会启动一个主线程,主线程启动时,会调用epoll的epoll_create函数创建一个epoll实例,并创建一个socket,调用listen函数把它转成监听socket,调epoll_ctl函数,注册到epoll实例中。然后主线程会调用epoll中的epoll_wait函数,监听注册到epoll实例中的所有socket,一旦有事件就绪就会进行事件分派,分派给acceptor或handler处理,这就是reactor的逻辑,

在这里插入图片描述

当注册到epoll实例中的socket有事件就绪,epoll_wait函数就会返回,当前线程就会遍历有事件就绪的socket,根据事件类型进行事件分派。如果是建立连接事件,就会调用acceptor的逻辑处理,acceptor中的逻辑就是调用socket.accept()获取已建立连接的socket,然后调用epoll_ctl把该socket注册到epoll实例;如果是读写事件,就会调用handler的逻辑处理读写事件,读事件的处理就是调用socket.read()获取数据然后进行相应处理,写事件就是调用socket.write()把数据写出。

在这里插入图片描述

Redis的事件驱动框架

基于这种单线程reactor的IO模型,redis就封装出了自己的事件驱动框架。

在这里插入图片描述

整个Redis事件驱动框架的主体逻辑就是一个主线程的死循环,在循环中,当前线程调用epoll_wait进行监听,获取有事件就绪的socket,然后放入一个队列,所有socket都放入队列后,会遍历队列中的socket进行事件分派。如果是连接建立事件,就会调用socket.accept()建立连接,然后调用epoll_ctl函数把返回的socket注册到epoll实例中;如果是读就绪事件,就调用socket.read()函数读取客户端发送的数据,也就是客户端发来的redis命令,然后执行该redis命令对应的函数;如果是写就绪事件,则调用socket.write()函数把数据写出。

Redis的核心逻辑是单线程处理,但不表示Redis真的就只有一个线程,一些文件关闭、惰性删除、AOF文件刷盘、执行bgsave命令写内存快照等任务,还是由后台线程来执行,所以Redis并不是真正的单线程。

在这里插入图片描述

在Redis的6.0版本开始,引入了多线程IO读写机制,此时Redis的事件驱动框架,在处理IO读写时会使用多线程的方式进行处理,而核心逻辑(也就是redis的命令处理)还是由一个主线程执行。

在这里插入图片描述

Redis会把所有读就绪的socket以轮询的方式分配给所有IO线程处理,IO线程会读取socket中的数据,然后主线程等待所有的IO线程读取完毕,再进行命令处理。处理完毕后,需要把处理结果写回客户端时,Redis再次进行分配,把待写回数据的socket分配给IO线程进行数据写回。

这样,即保持了Redis单线程处理的核心逻辑不变,又通过多线程IO读写这种机制,提升了IO读写的速度,从而进一步提升Redis的性能。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ARTS Week 20

Algorithm 本周的算法题为 1222. 可以攻击国王的皇后 在一个 下标从 0 开始 的 8 x 8 棋盘上,可能有多个黑皇后和一个白国王。 给你一个二维整数数组 queens,其中 queens[i] [xQueeni, yQueeni] 表示第 i 个黑皇后在棋盘上的位置。还给你一个长度为 2 的…

Linux上安装torch-geometric(pyg)1.7.2踩坑记录

重点:1.一定要在创建虚拟环境的时候设置好python版本。2.一定要先确定使用1.X还是2.X的pyg库,二者不兼容。3.一定要将cuda、torch、pyg之间的版本对应好。所以,先确定pyg版本,再确定torch和cuda的版本。 结论:如果在u…

【兔子机器人】修改GO电机id(软件方法、硬件方法)

一、硬件方法 利用上位机直接修改GO电机的id号: 打开调试助手,点击“调试”,查询电机,修改id号,即可。 但先将四个GO电机连接线拔掉,不然会将连接的电机一并修改。 利用24V电源给GO电机供电。 二、软件方…

UDP与TCP:了解这两种网络协议的不同之处

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

实验二(一):IPV4编址及IPV4路由基础实验

一实验介绍 1.关于本实验 IPv4( Internet Protocol Version 4)是 TCP/IP 协议族中最为核心的协议之一。 它工作在 TCP/IP参考模型的网际互联层,该层与 OSI参考模型的网络层相对应。 网络层提供了无连接数据传输服务,即网络在发送分组时不需要先建立连…

BDD - Python Behave log 为每个 Scenario 生成对应的 log 文件

BDD - Python Behave log 为每个 Scenario 生成对应的 log 文件 引言应用 Behave 官网 Log 配置文件项目 SetupFeature 文件steps 文件Log 配置文件environment.py 文件behave.ini 执行结果 直接应用 Python logging 模块方式 1:应用 log 配置文件log 配置文件envir…

ubuntu23.10安装搜狗拼音

1.添加fcitx仓库 sudo add-apt-repository ppa:fcitx-team/nightly 更新: sudo apt-get update 安装fcitx sudo apt-get install fcitx fcitx安装成功 切换输入系统为fcitx

git命令行提交——github

1. 克隆仓库至本地 git clone 右键paste(github仓库地址) cd 仓库路径(进入到仓库内部准备提交文件等操作) 2. 查看main分支 git branch(列出本地仓库中的所有分支) 3. 创建新分支(可省…

Flink概述

1.什么是Flink 是一个框架和分布式处理引擎,用于对无界和有界数据流进行有状态计算。 官网:Flink 2.Flink的发展历史 Flink起源于一个叫作Stratosphere的项目,它是由3所地处柏林的大学和欧洲其他一些大学在2010~2014年共同进行的研究项目&a…

Yolov8模型用torch_pruning剪枝

目录 🚀🚀🚀订阅专栏,更新及时查看不迷路🚀🚀🚀 原理 遍历所有分组 高级剪枝器 🚀🚀🚀订阅专栏,更新及时查看不迷路🚀&#x1f680…

【重新定义matlab强大系列十七】Matlab深入浅出长短期记忆神经网络LSTM

🔗 运行环境:Matlab 🚩 撰写作者:左手の明天 🥇 精选专栏:《python》 🔥 推荐专栏:《算法研究》 #### 防伪水印——左手の明天 #### 💗 大家好🤗&#x1f91…

NPP VIIRS卫星数据介绍及获取

VIIRS(Visible infrared Imaging Radiometer)可见光红外成像辐射仪。扫描式成像辐射仪,可收集陆地、大气、冰层和海洋在可见光和红外波段的辐射图像。它是高分辨率辐射仪AVHRR和地球观测系列中分辨率成像光谱仪MODIS系列的拓展和改进。VIIRS数…

java 数据结构二叉树

目录 树 树的概念 树的表示形式 二叉树 两种特殊的二叉树 二叉树的性质 二叉树的存储 二叉树的基本操作 二叉树的遍历 二叉树的基本操作 二叉树oj题 树 树是一种 非线性 的数据结构,它是由 n ( n>0 )个有限结点组成一个具有层次…

vs创建asp.net core webapi发布到ISS服务器

打开服务器创建test123文件夹,并设置共享。 ISS配置信息: 邮件网站,添加网站 webapi asp.net core发布到ISS服务器网页无法打开解决方法 点击ISS Express测试,可以成功打开网页。 点击生成,发布到服务器 找到服务器IP…

OJ_复数集合

题干 C实现 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <queue> #include <string> using namespace std;struct Complex {int re;int im;//构造函数Complex(int _re, int _im) {//注意参数名字必须不同re _re;im _im;} };//结构体不支…

新闻文章分类项目

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 新闻文章分类模型比较项目报告 项目介绍 背景 新闻文章自动分类是自然语言处理和文本挖掘领域的一个重要任务。正确分类新闻文章不仅能帮助用…

日期问题---算法精讲

前言 今天讲讲日期问题&#xff0c;所谓日期问题&#xff0c;在蓝桥杯中出现众多&#xff0c;但是解法比较固定。 一般有判断日期合法性&#xff0c;判断是否闰年&#xff0c;判断日期的特殊形式&#xff08;回文或abababab型等&#xff09; 目录 例题 题2 题三 总结 …

问题:前端获取long型数值精度丢失,后面几位都为0

文章目录 问题分析解决 问题 通过接口获取到的数据和 Postman 获取到的数据不一样&#xff0c;仔细看 data 的第17位之后 分析 该字段类型是long类型问题&#xff1a;前端接收到数据后&#xff0c;发现精度丢失&#xff0c;当返回的结果超过17位的时候&#xff0c;后面的全…

[java入门到精通] 11 泛型,数据结构,List,Set

今日目标 泛型使用 数据结构 List Set 1 泛型 1.1 泛型的介绍 泛型是一种类型参数&#xff0c;专门用来保存类型用的 最早接触泛型是在ArrayList&#xff0c;这个E就是所谓的泛型了。使用ArrayList时&#xff0c;只要给E指定某一个类型&#xff0c;里面所有用到泛型的地…

【C++】函数重载

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:C ⚙️操作环境:Visual Studio 2022 目录 &#x1f4cc;函数重载的定义 &#x1f4cc;函数重载的三种类型 &#x1f38f;参数个数不同 &#x1f38f;参数类型不同 &#x1f38f;参数类型顺序不同 &#x1f4cc;重载…