【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的性能。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[java入门到精通] 18 字符流,编码表,对象流,其他流

今日目标 编码表 字符输出流 字符输入流 字符缓冲流 转换流 对象操作流 装饰模式 commons-iojar包 1 编码表 1.1 思考: 既然字节流可以操作所有文件,那么为什么还要学习字符流 ? 如果使用字节流 , 把文本文件中的内容读取到内存时…

ODP(Open Data Plane)

1. 摘要 本文档旨在指导新的ODP应用程序开发人员。 有关ODP的更多详细信息,请参见 ODP 主页。 Overview of a system running ODP applications ODP是一份API规范,为高性能网络应用程序的实现提供平台独立性、自动硬件加速和CPU扩展。 本文档介绍如何充…

DHCP中继实验(思科)

华为设备参考:DHCP中继实验(华为) 一,技术简介 DHCP中继,可以实现在不同子网和物理网段之间处理和转发DHCP信息的功能。如果DHCP客户机与DHCP服务器在同一个物理网段,则客户机可以正确地获得动态分配的IP…

OS-Copilot:实现具有自我完善能力的通用计算机智能体

🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ AI 缩小了人类间的知识和技术差距 论文标题:OS-Copilot: Towards Generalist Computer Agents with Self-Improvement 论文链接:https://arxiv.org/abs/2402.07456 项目主页&a…

Hadoop生态选择(一)

一、项目框架 1.1技术选型 技术选型主要考虑因素:维护成本、总成本预算、数据量大小、业务需求、行业内经验、技术成熟度。 数据采集传输:Flume,Kafka,DataX,Maxwell,Sqoop,Logstash数据存储:MySQL,HDFS…

全网最最最详细的centos7如何设置静态ip

以下步骤假设你已经有了管理员权限(或者可以使用sudo)以及你的网络接口名称(例如ens33)。 步骤 1: 查找网络接口名称 打开终端。运行命令nmcli d来查看所有网络设备及其状态。找到你想配置的设备名称,比如ens33。 步…

结构指针的使用

结构指针的使用 指针类型变量: 指针类型,是变量类型的一种,它是专门用来存储变量的地址的。 例如 int *p; 表示p是一个指针变量,它用来存储某个整型变量的地址。 int a5; int *p&a; 这样,就将整型变量a的地…

Python语言元素之变量

程序是指令的集合,写程序就是用指令控制计算机做我们想让它做的事情。那么,为什么要用Python语言来写程序呢?因为Python语言简单优雅,相比C、C、Java这样的编程语言,Python对初学者更加友好。 一、一些计算机常识 在…

YOLOv9最新的改进项目来了!!

专栏介绍:YOLOv9改进系列 | 包含深度学习最新创新,主力高效涨点!!! YOLOv9作为最新的YOLO系列模型,对于做目标检测的同学是必不可少的。本专栏将针对2024年最新推出的YOLOv9检测模型,使用当前流…

RabbitMQ - 06 - Topic交换机

目录 控制台创建队列与交换机 编写消费者方法 编写生产者测试方法 结果 Topic交换机与Direct交换机基本一致 可参考 这篇帖子 http://t.csdnimg.cn/AuvoK topic交换机与Direct交换机的区别是 Topic交换机接收的消息RoutingKey必须是多个单词,以 . 分割 Topic交…

虚拟化

什么是虚拟化 虚拟化(Virtualization)是一种资源分配和管理技术,是将计算机的各种实体资源,比如CPU、内存、磁盘空间、网络适配器等,进行抽象转换后虚拟的设备,可以实现灵活地分割、组合为一个或多个计算机配置环境,并…

初探深度学习-手写字体识别

前言 手写数字的神经网络识别通常指的是通过训练有素的神经网络模型来识别和分类手写数字图像的任务。这种类型的任务是机器学习和计算机视觉领域的一个经典问题,经常作为入门级的图像识别问题来展示和测试各种机器学习算法的能力。在实际应用中,手写数…

寒假作业Day 09

寒假作业Day 09 一、选择题 因为一开始的for循环&#xff0c;k<2NN&#xff0c;所以复杂度为2N方&#xff0c;而后面的M10的while循环&#xff0c;则是10&#xff0c;复杂度为常数级&#xff0c;所以2N方10&#xff0c;近似于N方&#xff0c;即O(N^2) 这是一个计算阶乘的递…

excel批量数据导入时用poi将数据转化成指定实体工具类

1.实现目标 excel进行批量数据导入时&#xff0c;将批量数据转化成指定的实体集合用于数据操作&#xff0c;实现思路&#xff1a;使用注解将属性与表格中的标题进行同名绑定来赋值。 2.代码实现 2.1 目录截图如下 2.2 代码实现 package poi.constants;/*** description: 用…

一键部署Tesseract-OCR环境C++版本(Windows)

环境&#xff1a;Windows 10 工具&#xff1a;git vcpkg vscode cmake 库&#xff1a;Tesseract 一键部署Tesseract-OCR环境C版本&#xff08;Windows&#xff09; 分享这篇文章的原因很简单&#xff0c;就是为了让后续的朋友少走弯路。自己在搜索相关C版本的tesseract部署时…

【python量化】基于okex API开发的海龟策略

介绍 基于okex api开发的海龟策略&#xff0c;okex海龟策略python实现方式。该程序目前只支持单品种&#xff0c;比如设置ETH后&#xff0c;只对ETH进行做多做空。该程序运行需要两样东西&#xff1a;apikey 和 标的 运行该程序之前&#xff0c;用户需要到okex网站去申请apiK…

虚函数与纯虚函数有什么区别?

总的来说有两点区别&#xff1a; 1.虚函数的作用主要是矫正指针&#xff08;口语化的说法&#xff09; 2.虚函数不一定要重新定义&#xff0c;纯虚函数一定要定义&#xff08;口语化的说法&#xff09; 1&#xff09;. 虚函数的作用主要是矫正指针&#xff0c;使得基类的指针…

【Python数据结构与判断1/7】复杂的多向选择

目录 导入 举个栗子 代码优化 elif 栗子 执行顺序 情况一 情况二 情况三 if-elif-else特性 三种判断语句小结 if if-else if-elif-else 嵌套语句 if嵌套 栗子 执行顺序 相互嵌套 Tips Debug 总结 导入 在前面&#xff0c;我们学习了单向选择的if语句和多项…

Decontam去污染:一个尝试

为了程序运行的便利性&#xff0c;不想将Decontam放到windows的Rstudio里面运行&#xff0c;需要直接在Ubuntu中运行&#xff0c;并且为了在Decontam时进行其他操作&#xff0c;使用python去运行R 首先你需要有一个conda环境&#xff0c;安装了R&#xff0c;Decontam&#xff0…

day 49 动态规划 part 10● 121. 买卖股票的最佳时机 ● 122.买卖股票的最佳时机II

看了题解&#xff0c;第一种暴力&#xff0c;两个for循环。 class Solution { public:int maxProfit(vector<int>& prices) {int result 0;for (int i 0; i < prices.size(); i) {for (int j i 1; j < prices.size(); j){result max(result, prices[j] -…