Redis的IO模型

news2025/1/10 21:04:46

Redis IO模型

Redis IO模型 使用的是基于 Reactor 模式的 I/O 多路复用模型。这个模型通过单线程事件循环来处理所有的客户端请求和响应。

基本模式

1. Reactor 模式

Reactor 模式是一种用于处理并发 I/O 操作的设计模式。它包含以下几个组件:

  • 多路复用器(Multiplexer):负责监听多个 I/O 事件,如读、写、连接等。
  • 事件处理器(Event Handler):处理特定事件的回调函数。

2. Redis 的 I/O 多路复用

Redis 使用操作系统提供的 I/O 多路复用机制,如 selectpollepoll 或 kqueue。这些机制可以在单个线程中监视多个文件描述符,以便在任何一个描述符准备好进行 I/O 操作时通知应用程序。

主要步骤:
  1. 事件循环初始化:创建和初始化事件循环及相应的多路复用器。
  2. 事件注册:将客户端套接字上的读写事件注册到多路复用器。
  3. 事件等待:调用多路复用器的方法,如 select 或 epoll_wait,等待事件发生。
  4. 事件分发:当事件发生时,多路复用器会返回就绪的文件描述符列表。
  5. 事件处理:根据事件类型调用相应的事件处理器(读事件、写事件等)。
  6. 响应客户端:将处理结果返回给客户端。

基本原理

Redis 的 I/O 模型实现原理,需要深入了解其事件驱动框架和多路复用机制。

1. 事件驱动框架

Redis 的事件驱动框架主要由以下几个组件组成:

  • 事件循环(Event Loop):这是事件驱动模型的核心,负责管理所有的 I/O 事件。
  • 事件类型(Event Types):Redis 主要处理两种事件:文件事件(File Events)和时间事件(Time Events)。
  • 事件处理器(Event Handlers):每个事件类型都有相应的事件处理器。

Redis 使用 aeEventLoop 结构体来管理事件循环,包含了文件事件和时间事件的注册、取消、处理等功能。

2. I/O 多路复用

Redis 使用操作系统提供的 I/O 多路复用机制,如 selectpollepoll(Linux)或 kqueue(BSD系统),这些系统调用允许一个线程同时监视多个文件描述符。

多路复用器(Multiplexer)

在 Redis 中,多路复用器通过 aeApi 结构体进行抽象,并根据操作系统的不同实现选择不同的多路复用策略:

  • ae_select.c:基于 select 系统调用。
  • ae_epoll.c:基于 epoll 系统调用。
  • ae_kqueue.c:基于 kqueue 系统调用。

3. Redis 的事件处理流程

Redis 的事件处理流程大致如下:

事件循环初始化
aeEventLoop *aeCreateEventLoop(int setsize) {
    aeEventLoop *eventLoop = zmalloc(sizeof(*eventLoop));

    // 初始化事件循环
    eventLoop->events = zmalloc(sizeof(aeFileEvent)*setsize);
    eventLoop->fired = zmalloc(sizeof(aeFiredEvent)*setsize);
    eventLoop->setsize = setsize;
    eventLoop->timeEventHead = NULL;
    eventLoop->timeEventNextId = 0;
    eventLoop->stop = 0;

    // 初始化多路复用API
    if (aeApiCreate(eventLoop) == -1) {
        zfree(eventLoop->events);
        zfree(eventLoop->fired);
        zfree(eventLoop);
        return NULL;
    }

    return eventLoop;
}
事件注册
int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
                      aeFileProc *proc, void *clientData) {
    if (fd >= eventLoop->setsize) return AE_ERR;

    aeFileEvent *fe = &eventLoop->events[fd];
    if (aeApiAddEvent(eventLoop, fd, mask) == -1)
        return AE_ERR;

    fe->mask |= mask;
    if (mask & AE_READABLE) fe->rfileProc = proc;
    if (mask & AE_WRITABLE) fe->wfileProc = proc;
    fe->clientData = clientData;

    return AE_OK;
}
事件等待
int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
    int retval, numevents = 0;

    retval = epoll_wait(eventLoop->apidata->epfd, eventLoop->apidata->events,
                        eventLoop->setsize, 
                        tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1);

    if (retval > 0) {
        int j;

        numevents = retval;
        for (j = 0; j < numevents; j++) {
            int mask = 0;
            struct epoll_event *e = eventLoop->apidata->events+j;

            if (e->events & EPOLLIN) mask |= AE_READABLE;
            if (e->events & EPOLLOUT) mask |= AE_WRITABLE;
            if (e->events & EPOLLERR) mask |= AE_WRITABLE;
            if (e->events & EPOLLHUP) mask |= AE_WRITABLE;

            eventLoop->fired[j].fd = e->data.fd;
            eventLoop->fired[j].mask = mask;
        }
    }

    return numevents;
}
事件处理
void aeProcessEvents(aeEventLoop *eventLoop, int flags) {
    int processed = 0, numevents;

    if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return;

    if (eventLoop->maxfd != -1) {
        numevents = aeApiPoll(eventLoop, tvp);
        for (j = 0; j < numevents; j++) {
            aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];
            int mask = eventLoop->fired[j].mask;
            int fd = eventLoop->fired[j].fd;
            int rfired = 0;

            if (fe->mask & mask & AE_READABLE) {
                rfired = 1;
                fe->rfileProc(eventLoop,fd,fe->clientData,mask);
            }
            if (fe->mask & mask & AE_WRITABLE) {
                if (!rfired || fe->wfileProc != fe->rfileProc)
                    fe->wfileProc(eventLoop,fd,fe->clientData,mask);
            }
            processed++;
        }
    }

    if (flags & AE_TIME_EVENTS)
        processed += processTimeEvents(eventLoop);

    return processed;
}

单线程的优势

  • 避免锁竞争:由于 Redis 运行在单线程中,所有操作都是原子的,不需要加锁机制来保护共享资源,简化了实现。
  • CPU 缓存友好:在单线程中,数据访问模式更加线性,减少了 CPU 缓存失效,提高了缓存命中率。
  • 性能:由于 Redis 的大部分操作是内存操作,并且操作系统的多路复用机制非常高效,单线程模型能够提供足够高的性能。
  • 原子性:单线程模型确保每个命令是原子执行的,不会出现数据竞争问题。

关于ArchManual

https://archmanual.com

https://github.com/yingqiangh/ArchManual

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

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

相关文章

构建高效入学审核系统:Spring Boot解决方案

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理大学生入学审核系统的相关信息成为必然。开…

redis常见的数据类型?

参考&#xff1a;一文读懂Redis五种数据类型及应用场景 - 知乎 (zhihu.com) String 类型 String 类型&#xff1a;Redis 最基本的数据类型&#xff0c;它是二进制安全的&#xff0c;意味着你可以用它来存储任何类型的数据&#xff0c;如图片、序列化对象等。使用场景&#xff…

OceanBase 运维管理工具 OCP 4.x 升级:聚焦高可用、易用性及可观测性

可视化的管控平台&#xff0c;对 OceanBase 这类的分布式数据库及大规模数据的运维管理来说&#xff0c;是提升运维效率与数据库管理水平的重要工具。OceanBase 运维管理工具 OCP 作为专为OceanBase数据库设计的企业级全生命周期管理平台&#xff0c;为用户提供了全面的数据库可…

句子成分——每日一划(六)

顺手简答一划&#xff1a;And&#xff1a;连词 you&#xff1a;主语 my friend&#xff1a;插入语 you&#xff1a;对主语起强调作用 are&#xff1a;系动词 the real hero&#xff1a;表语 目录 一、原句 二、独立成分&#xff0c;状语(Adverbial Phrase) 三、条件状语从…

Leetcode面试经典150题-82.删除排序链表中的重复元素II

之前写过这个题的基础第83题&#xff0c;看本文之前一定要先看懂这个Leetcode面试经典150题-82.删除排序链表中的重复元素II前序-83.删除排序链表中的重复元素_删除链表中重复的元素-CSDN博客 直接上代码了&#xff0c;解法都在代码里&#xff0c;不懂就留言或者私信 /*** De…

电机驱动开发之驱动板

目录 1.主要器件选型2.原理图设计3.PCB绘制电源调理驱动电路电流反馈位置反馈 4.PCB绘制5.打板验证6.总结 1.主要器件选型 器件参数封装理由LDOLM317DCYR &#xff08;24V-12V 12V-5V&#xff09;SOT-223小电流应用 LDO比DCDC噪声小响应快更为稳定预驱FD6288TTssop-20常见无刷…

独立站新纪元:破局而出,共绘可持续发展蓝图

随着全球电商市场的日益繁荣与平台竞争的加剧,独立站作为商家自主掌控品牌与市场的桥头堡,正面临着前所未有的挑战与机遇。在这个瞬息万变的时代,如何在平台垄断的阴影下突围而出,实现可持续增长,成为了每一位独立站商家亟需解答的课题。为此,店匠科技( Shoplazza ) 将于 9月 2…

基于SpringBoot+Vue的高校竞赛管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的…

2024年程序员接单平台汇总,程序员偷偷赚钱的机会来了!

作为技术创新的推动者和代码的创造者&#xff0c;程序员的影响力早已跨越国界。来到2024年&#xff0c;程序员不仅着眼于眼前的一亩三分地&#xff0c;也慢慢将眼光投向了外包接单。 程序员外包接单作为程序员副业的一种常见形式&#xff0c;给程序员带来了更多的选择&#xf…

C盘维护和清理心得(磁盘清理亲身实践)

01 安装软件前要自定义 安装软件都是默认C盘 通常可以选择安装储存位置至于应用数据会自动存在C盘&#xff0c;但一般并不大 02 安装后自定义存储位置 各种储存位置当然也默认C盘&#xff0c;通常分为下载位置和缓存位置 最经典的微信&#xff0c;QQ&#xff0c;钉钉等社交…

后台数据库查询记录

一、根据日期按天分组查询倒序 //mapper public List<Date> dateByPatientId(FollowScheme followScheme); <select id"dateByPatientId" parameterType"com.ruoyi.follow.domain.FollowScheme" resultType"java.util.Date">SELECT…

Redis:发布(pub)与订阅(sub)实战

前言 Redis发布订阅&#xff08;Pub/Sub&#xff09;是Redis提供的一种消息传递机制&#xff0c;它使用“发布者-订阅者”&#xff08;publisher-subscriber&#xff09;模式来处理消息传递。在这种模式下&#xff0c;发布者将消息发布到一组订阅者中&#xff0c;而无需关心谁…

C++八股总结(不间断更新)

数据类型和大小&#xff08;32位和64位&#xff09; char&#xff1a;1字节 1字节 short&#xff1a;2字节 2字节 int&#xff1a;4字节 4字节 long&#xff1a;4字节 8字节 long long&#xff1a;8字节 8字节 new-delete malloc-free new是C中的关键字。new可以根据动态分配内…

中等职业学校新媒体一键分发软件实训室解决方案

一、产品介绍 新媒体一键分发软件实训平台是专为中等职业学校设计&#xff0c;以满足新媒体运营、营销等岗位需求的教育解决方案。该平台通过模拟真实的新媒体工作环境&#xff0c;提供账号管理、内容编辑、一键分发等功能&#xff0c;使学生能够在实际操作中掌握新媒体技术的…

Java 回顾方法的定义

一、方法的定义 1&#xff0e;修饰符&#xff08;public static…&#xff09;详见博客【Java 方法的定义】 2&#xff0e;返回值&#xff08;int, double, char[],…., void&#xff09;详见博客【Java 方法的定义】 3. break&#xff1a;跳出switch 结束循环&#xff0c;详…

西门子S7协议(PROFINET端口)转罗克韦尔AB的Ethernet/IP网络通讯

智能网关IGT-DSER支持多种PLC之间、PLC与智能仪表之间多对多通讯&#xff0c;支持以太网&#xff0c;串口设备混合数据交换&#xff1b;无需PLC内编程开发&#xff0c;只需在智能网关的参数管理软件上配置数据的起始地址和数量即可&#xff0c;支持热插拔&#xff0c;断电断网后…

gazebo 中车子静态(不设置速度)滑动的问题

目录 写在前面的话&#xff08;重要&#xff01;&#xff01;&#xff01;&#xff09;gazebo中的参数设置设置启动小车的初始姿态 发现车子与地面的接触点有问题&#xff08;关键&#xff01;&#xff01;&#xff01;&#xff09;查看接触点的步骤&#xff1a;原始车轮设置原…

实现mini-redis字符串操作

写在文章开头 在之前的系列文章中&#xff0c;我们通过命令行模式完成了mini-redis解析和处理指令的执行基调&#xff0c;这篇文章笔者将对mini-redis中存储字符串的set和get指令的设计和实现进行分析讲解&#xff0c;希望对你了解mini-redis有所帮助。 Hi&#xff0c;我是 sh…

94 、k8s之rbac

一、rbac----安全机制 赋权机制 集群是按照用户名进行登录&#xff0c;按照项目名称进行命名空间的分类。 配电云主站------62天 8个人 高温补贴 一主2从 user pdyzz pdyzz -n pdyzz 资源空间 pod数量 1.1、k8s的安全机制&#xff1a; apiserver------>集群内和外…

S3C2440开发板点亮LED灯+PWM定时器

目录 GPIO引脚和寄存器概述 点亮LED灯步骤 1.配置GPIO 2.点亮LED 设置引脚为输出 控制引脚电平 完整代码 PWM GPIO引脚和寄存器概述 GPIO端口&#xff1a; S3C2440的GPIO引脚可被配置为输入或输出&#xff08;控制LED的引脚通常配置为输出模式&#xff09;。寄存器&#…