Redis原理篇:网络模型剖析
目录1.网络模型1.1 用户空间和内核态空间1.2.网络模型-阻塞IO1.3 网络模型-非阻塞IO1.4 网络模型-IO多路复用1.5 网络模型-IO多路复用-select方式1.6 网络模型-IO多路复用模型-poll模式1.7 网络模型-IO多路复用模型-epoll函数1.8、网络模型-epoll中的ET和LT1.9 网络模型-基于epoll的服务器端流程1.0 .网络模型-信号驱动1.0.1 异步IO1.0.2 对比2.Redis网络模型-Redis是单线程的吗为什么使用单线程2.1.Redis的单线程模型-Redis单线程和多线程网络模型变更1.网络模型1.1 用户空间和内核态空间服务器大多都采用Linux系统这里我们以Linux为例来讲解:ubuntu和Centos 都是Linux的发行版发行版可以看成对linux包了一层壳任何Linux发行版其系统内核都是Linux。我们的应用都需要通过Linux内核与硬件交互用户的应用比如redismysql等其实是没有办法去执行访问我们操作系统的硬件的所以我们可以通过发行版的这个壳子去访问内核再通过内核去访问计算机硬件计算机硬件包括如cpu内存网卡等等内核通过寻址空间可以操作硬件的但是内核需要不同设备的驱动有了这些驱动之后内核就可以去对计算机硬件去进行 内存管理文件系统的管理进程的管理等等我们想要用户的应用来访问计算机就必须要通过对外暴露的一些接口才能访问到从而简介的实现对内核的操控但是内核本身上来说也是一个应用所以他本身也需要一些内存cpu等设备资源用户应用本身也在消耗这些资源如果不加任何限制用户去操作随意的去操作我们的资源就有可能导致一些冲突甚至有可能导致我们的系统出现无法运行的问题因此我们需要把用户和内核隔离开进程的寻址空间划分成两部分内核空间、用户空间什么是寻址空间呢我们的应用程序也好还是内核空间也好都是没有办法直接去物理内存的而是通过分配一些虚拟内存映射到物理内存中我们的内核和应用程序去访问虚拟内存的时候就需要一个虚拟地址这个地址是一个无符号的整数比如一个32位的操作系统他的带宽就是32他的虚拟地址就是2的32次方也就是说他寻址的范围就是0~2的32次方 这片寻址空间对应的就是2的32个字节就是4GB这个4GB会有3个GB分给用户空间会有1GB给内核系统在linux中他们权限分成两个等级0和3用户空间只能执行受限的命令Ring3而且不能直接调用系统资源必须通过内核提供的接口来访问内核空间可以执行特权命令Ring0调用一切系统资源所以一般情况下用户的操作是运行在用户空间而内核运行的数据是在内核空间的而有的情况下一个应用程序需要去调用一些特权资源去调用一些内核空间的操作所以此时他俩需要在用户态和内核态之间进行切换。比如Linux系统为了提高IO效率会在用户空间和内核空间都加入缓冲区写数据时要把用户缓冲数据拷贝到内核缓冲区然后写入设备读数据时要从设备读取数据到内核缓冲区然后拷贝到用户缓冲区针对这个操作我们的用户在写读数据时会去向内核态申请想要读取内核的数据而内核数据要去等待驱动程序从硬件上读取数据当从磁盘上加载到数据之后内核会将数据写入到内核的缓冲区中然后再将数据拷贝到用户态的buffer中然后再返回给应用程序整体而言速度慢就是这个原因为了加速我们希望read也好还是wait for data也最好都不要等待或者时间尽量的短。1.2.网络模型-阻塞IO在《UNIX网络编程》一书中总结归纳了5种IO模型阻塞IOBlocking IO非阻塞IONonblocking IOIO多路复用IO Multiplexing信号驱动IOSignal Driven IO异步IOAsynchronous IO应用程序想要去读取数据他是无法直接去读取磁盘数据的他需要先到内核里边去等待内核操作硬件拿到数据这个过程就是1是需要等待的等到内核从磁盘上把数据加载出来之后再把这个数据写给用户的缓存区这个过程是2如果是阻塞IO那么整个过程中用户从发起读请求开始一直到读取到数据都是一个阻塞状态。具体流程如下图用户去读取数据时会去先发起recvform一个命令去尝试从内核上加载数据如果内核没有数据那么用户就会等待此时内核会去从硬件上读取数据内核读取数据之后会把数据拷贝到用户态并且返回ok整个过程都是阻塞等待的这就是阻塞IO总结如下顾名思义阻塞IO就是两个阶段都必须阻塞等待阶段一用户进程尝试读取数据比如网卡数据此时数据尚未到达内核需要等待数据此时用户进程也处于阻塞状态阶段二数据到达并拷贝到内核缓冲区代表已就绪将内核数据拷贝到用户缓冲区拷贝过程中用户进程依然阻塞等待拷贝完成用户进程解除阻塞处理数据可以看到阻塞IO模型中用户进程在两个阶段都是阻塞状态。1.3 网络模型-非阻塞IO顾名思义非阻塞IO的recvfrom操作会立即返回结果而不是阻塞用户进程。阶段一用户进程尝试读取数据比如网卡数据此时数据尚未到达内核需要等待数据返回异常给用户进程用户进程拿到error后再次尝试读取循环往复直到数据就绪阶段二将内核数据拷贝到用户缓冲区拷贝过程中用户进程依然阻塞等待拷贝完成用户进程解除阻塞处理数据可以看到非阻塞IO模型中用户进程在第一个阶段是非阻塞第二个阶段是阻塞状态。虽然是非阻塞但性能并没有得到提高。而且忙等机制会导致CPU空转CPU使用率暴增。1.4 网络模型-IO多路复用无论是阻塞IO还是非阻塞IO用户应用在一阶段都需要调用recvfrom来获取数据差别在于无数据时的处理方案如果调用recvfrom时恰好没有数据阻塞IO会使CPU阻塞非阻塞IO使CPU空转都不能充分发挥CPU的作用。 如果调用recvfrom时恰好有数据则用户进程可以直接进入第二阶段读取并处理数据所以怎么看起来以上两种方式性能都不好而在单线程情况下只能依次处理IO事件如果正在处理的IO事件恰好未就绪数据不可读或不可写线程就会被阻塞所有IO事件都必须等待性能自然会很差。就比如服务员给顾客点餐分两步顾客思考要吃什么等待数据就绪顾客想好了开始点餐读取数据要提高效率有几种办法方案一增加更多服务员多线程 方案二不排队谁想好了吃什么数据就绪了服务员就给谁点餐用户应用就去读取数据那么问题来了用户进程如何知道内核中数据是否就绪呢所以接下来就需要详细的来解决多路复用模型是如何知道到底怎么知道内核数据是否就绪的问题了这个问题的解决依赖于提出的文件描述符File Descriptor简称FD是一个从0 开始的无符号整数用来关联Linux中的一个文件。在Linux中一切皆文件例如常规文件、视频、硬件设备等当然也包括网络套接字Socket。通过FD我们的网络模型可以利用一个线程监听多个FD并在某个FD可读、可写时得到通知从而避免无效的等待充分利用CPU资源。阶段一用户进程调用select指定要监听的FD集合核监听FD对应的多个socket任意一个或多个socket数据就绪则返回readable此过程中用户进程阻塞阶段二用户进程找到就绪的socket依次调用recvfrom读取数据内核将数据拷贝到用户空间用户进程处理数据当用户去读取数据的时候不再去直接调用recvfrom了而是调用select的函数select函数会将需要监听的数据交给内核由内核去检查这些数据是否就绪了如果说这个数据就绪了就会通知应用程序数据就绪然后来读取数据再从内核中把数据拷贝给用户态完成数据处理如果N多个FD一个都没处理完此时就进行等待。用IO复用模式可以确保去读数据的时候数据是一定存在的他的效率比原来的阻塞IO和非阻塞IO性能都要高IO多路复用是利用单个线程来同时监听多个FD并在某个FD可读、可写时得到通知从而避免无效的等待充分利用CPU资源。不过监听FD的方式、通知的方式又有多种实现常见的有selectpollepoll其中select和pool相当于是当被监听的数据准备好之后他会把你监听的FD整个数据都发给你你需要到整个FD中去找哪些是处理好了的需要通过遍历的方式所以性能也并不是那么好而epoll则相当于内核准备好了之后他会把准备好的数据直接发给你咱们就省去了遍历的动作。1.5 网络模型-IO多路复用-select方式select是Linux最早是由的I/O多路复用技术简单说就是我们把需要处理的数据封装成FD然后在用户态时创建一个fd的集合这个集合的大小是要监听的那个FD的最大值1但是大小整体是有限制的 这个集合的长度大小是有限制的同时在这个集合中标明出来我们要控制哪些数据比如要监听的数据是1,2,5三个数据此时会执行select函数然后将整个fd发给内核态内核态会去遍历用户态传递过来的数据如果发现这里边都数据都没有就绪就休眠直到有数据准备好时就会被唤醒唤醒之后再次遍历一遍看看谁准备好了然后再将处理掉没有准备好的数据最后再将这个FD集合写回到用户态中去此时用户态就知道了奥有人准备好了但是对于用户态而言并不知道谁处理好了所以用户态也需要去进行遍历然后找到对应准备好数据的节点再去发起读请求我们会发现这种模式下他虽然比阻塞IO和非阻塞IO好但是依然有些麻烦的事情 比如说频繁的传递fd集合频繁的去遍历FD等问题1.6 网络模型-IO多路复用模型-poll模式poll模式对select模式做了简单改进但性能提升不明显部分关键代码如下IO流程创建pollfd数组向其中添加关注的fd信息数组大小自定义调用poll函数将pollfd数组拷贝到内核空间转链表存储无上限内核遍历fd判断是否就绪数据就绪或超时后拷贝pollfd数组到用户空间返回就绪fd数量n用户进程判断n是否大于0,大于0则遍历pollfd数组找到就绪的fd与select对比select模式中的fd_set大小固定为1024而pollfd在内核中采用链表理论上无上限监听FD越多每次遍历消耗时间也越久性能反而会下降1.7 网络模型-IO多路复用模型-epoll函数epoll模式是对select和poll的改进它提供了三个函数第一个是eventpoll的函数他内部包含两个东西一个是1、红黑树- 记录的事要监听的FD2、一个是链表-一个链表记录的是就绪的FD紧接着调用epoll_ctl操作将要监听的数据添加到红黑树上去并且给每个fd设置一个监听函数这个函数会在fd数据就绪时触发就是准备好了现在就把fd把数据添加到list_head中去3、调用epoll_wait函数就去等待在用户态创建一个空的events数组当就绪之后我们的回调函数会把数据添加到list_head中去当调用这个函数的时候会去检查list_head当然这个过程需要参考配置的等待时间可以等一定时间也可以一直等 如果在此过程中检查到了list_head中有数据会将数据添加到链表中此时将数据放入到events数组中并且返回对应的操作的数量用户态的此时收到响应后从events中拿到对应准备好的数据的节点再去调用方法去拿数据。小总结select模式存在的三个问题能监听的FD最大不超过1024每次select都需要把所有要监听的FD都拷贝到内核空间每次都要遍历所有FD来判断就绪状态poll模式的问题poll利用链表解决了select中监听FD上限的问题但依然要遍历所有FD如果监听较多性能会下降epoll模式中如何解决这些问题的基于epoll实例中的红黑树保存要监听的FD理论上无上限而且增删改查效率都非常高每个FD只需要执行一次epoll_ctl添加到红黑树以后每次epol_wait无需传递任何参数无需重复拷贝FD到内核空间利用ep_poll_callback机制来监听FD状态无需遍历所有FD因此性能不会随监听的FD数量增多而下降1.8、网络模型-epoll中的ET和LT当FD有数据可读时我们调用epoll_wait或者select、poll可以得到通知。但是事件通知的模式有两种LevelTriggered简称LT也叫做水平触发。只要某个FD中有数据可读每次调用epoll_wait都会得到通知。EdgeTriggered简称ET也叫做边沿触发。只有在某个FD有状态变化时调用epoll_wait才会被通知。举个栗子假设一个客户端socket对应的FD已经注册到了epoll实例中客户端socket发送了2kb的数据服务端调用epoll_wait得到通知说FD就绪服务端从FD读取了1kb数据回到步骤3再次调用epoll_wait形成循环结论如果我们采用LT模式因为FD中仍有1kb数据则第⑤步依然会返回结果并且得到通知 如果我们采用ET模式因为第③步已经消费了FD可读事件第⑤步FD状态没有变化因此epoll_wait不会返回数据无法读取客户端响应超时。1.9 网络模型-基于epoll的服务器端流程我们来梳理一下这张图服务器启动以后服务端会去调用epoll_create创建一个epoll实例epoll实例中包含两个数据1、红黑树为空rb_root 用来去记录需要被监听的FD2、链表为空list_head用来存放已经就绪的FD创建好了之后会去调用epoll_ctl函数此函数会会将需要监听的数据添加到rb_root中去并且对当前这些存在于红黑树的节点设置回调函数当这些被监听的数据一旦准备完成就会被调用而调用的结果就是将红黑树的fd添加到list_head中去(但是此时并没有完成)3、当第二步完成后就会调用epoll_wait函数这个函数会去校验是否有数据准备完毕因为数据一旦准备就绪就会被回调函数添加到list_head中在等待了一段时间后(可以进行配置)如果等够了超时时间则返回没有数据如果有则进一步判断当前是什么事件如果是建立连接时间则调用accept() 接受客户端socket拿到建立连接的socket然后建立起来连接如果是其他事件则把数据进行写出1.0 .网络模型-信号驱动信号驱动IO是与内核建立SIGIO的信号关联并设置回调当内核有FD就绪时会发出SIGIO信号通知用户期间用户应用可以执行其它业务无需阻塞等待。阶段一用户进程调用sigaction注册信号处理函数内核返回成功开始监听FD用户进程不阻塞等待可以执行其它业务当内核数据就绪后回调用户进程的SIGIO处理函数阶段二收到SIGIO回调信号调用recvfrom读取内核将数据拷贝到用户空间用户进程处理数据当有大量IO操作时信号较多SIGIO处理函数不能及时处理可能导致信号队列溢出而且内核空间与用户空间的频繁信号交互性能也较低。1.0.1 异步IO这种方式不仅仅是用户态在试图读取数据后不阻塞而且当内核的数据准备完成后也不会阻塞他会由内核将所有数据处理完成后由内核将数据写入到用户态中然后才算完成所以性能极高不会有任何阻塞全部都由内核完成可以看到异步IO模型中用户进程在两个阶段都是非阻塞状态。1.0.2 对比最后用一幅图来说明他们之间的区别2.Redis网络模型-Redis是单线程的吗为什么使用单线程Redis到底是单线程还是多线程如果仅仅聊Redis的核心业务部分命令处理答案是单线程如果是聊整个Redis那么答案就是多线程在Redis版本迭代过程中在两个重要的时间节点上引入了多线程的支持Redis v4.0引入多线程异步处理一些耗时较旧的任务例如异步删除命令unlinkRedis v6.0在核心网络模型中引入 多线程进一步提高对于多核CPU的利用率因此对于Redis的核心网络模型在Redis 6.0之前确实都是单线程。是利用epollLinux系统这样的IO多路复用技术在事件循环中不断处理客户端情况。为什么Redis要选择单线程抛开持久化不谈Redis是纯 内存操作执行速度非常快它的性能瓶颈是网络延迟而不是执行速度因此多线程并不会带来巨大的性能提升。多线程会导致过多的上下文切换带来不必要的开销引入多线程会面临线程安全问题必然要引入线程锁这样的安全手段实现复杂度增高而且性能也会大打折扣2.1.Redis的单线程模型-Redis单线程和多线程网络模型变更当我们的客户端想要去连接我们服务器会去先到IO多路复用模型去进行排队会有一个连接应答处理器他会去接受读请求然后又把读请求注册到具体模型中去此时这些建立起来的连接如果是客户端请求处理器去进行执行命令时他会去把数据读取出来然后把数据放入到client中 clinet去解析当前的命令转化为redis认识的命令接下来就开始处理这些命令从redis中的command中找到这些命令然后就真正的去操作对应的数据了当数据操作完成后会去找到命令回复处理器再由他将数据写出。

相关新闻

如何从0开始搭建一个大语言模型并进一步训练微调?

如何从0开始搭建一个大语言模型并进一步训练微调?

生成式AI技术已成为产业升级的新晋引擎,加速推动数字经济高速发展,开发者则需要快速掌握生成式 AI 技能,并熟练掌握领先的工具平台,在竞争激烈的技术变革时代脱颖而出,实现“技术躺赢”。 知识增强类大语言模型作为生成…

2026/7/6 16:20:18 阅读更多 →
魔兽争霸III兼容性解决方案:从启动到体验的全方位优化指南

魔兽争霸III兼容性解决方案:从启动到体验的全方位优化指南

魔兽争霸III兼容性解决方案:从启动到体验的全方位优化指南 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 当你双击魔兽争霸III图标却只看…

2026/7/6 15:23:13 阅读更多 →
QMC音频格式转换全攻略:从跨设备播放难题到无损解码解决方案

QMC音频格式转换全攻略:从跨设备播放难题到无损解码解决方案

QMC音频格式转换全攻略:从跨设备播放难题到无损解码解决方案 【免费下载链接】QMCDecode QQ音乐QMC格式转换为普通格式(qmcflac转flac,qmc0,qmc3转mp3, mflac,mflac0等转flac),仅支持macOS,可自动识别到QQ音乐下载目录&#xff0c…

2026/5/17 6:45:44 阅读更多 →

最新新闻

完整数字通信链路仿真(哈夫曼 +(7,4) 汉明码 + BSC 信道)【P124302151陈明】

完整数字通信链路仿真(哈夫曼 +(7,4) 汉明码 + BSC 信道)【P124302151陈明】

一、摘要 本文搭建一套端到端简易数字通信系统,完整流程:随机信源序列→哈夫曼无损压缩(信源编码)→(7,4) 汉明码信道纠错编码→BSC 二进制对称信道加噪声传输→汉明译码纠错→哈夫曼译码恢复原始信源。通过改变 BSC 信道交叉概率…

2026/7/7 3:04:27 阅读更多 →
别再等别人盖章了:成年人最顶级的自由,是自己给自己打分

别再等别人盖章了:成年人最顶级的自由,是自己给自己打分

高铁穿过一段长长的隧道,车厢里暗了下来。车窗变成了一面模糊的镜子。我盯着镜子里那张略显疲惫的脸看了两秒,然后按熄了手机屏幕。就在刚刚,我还在反复刷新微信,等着下午刚汇报完的客户大老板给个反馈。十分钟没回,我…

2026/7/7 3:04:27 阅读更多 →
珍惜作为“牛马”的最后光阴?优必选,抛出了一个公关“核弹”

珍惜作为“牛马”的最后光阴?优必选,抛出了一个公关“核弹”

作者:Evin编辑:刘致呈审核:徐徐出品:互联网江湖这两年,机器人行业发展的非常快。从上春晚秀“舞技”,到跑马拉松破人类记录,再到进入电力、矿山等高危场景完成巡检等任务,机器人的价…

2026/7/7 3:02:26 阅读更多 →
AI视频生成技术在游戏特效制作中的应用实践

AI视频生成技术在游戏特效制作中的应用实践

🚀 30款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度 这次我们来看一个基于AI视频生成技术的"恐惧魔王 吞噬魔法"特效测试项目。这个项目展示了如何利用AI技术实现游戏角色特效的…

2026/7/7 2:40:13 阅读更多 →
本地AI部署实战指南:从环境配置到性能优化的完整解决方案

本地AI部署实战指南:从环境配置到性能优化的完整解决方案

🚀 30款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度 今天我们来聊聊一个让很多开发者头疼的问题:本地AI部署。虽然标题提到了"一人公司"的困境,但本文重…

2026/7/7 2:38:12 阅读更多 →
Claude偷改了你一行代码

Claude偷改了你一行代码

摘要:2026 年 6 月底,Reddit 开发者逆向 Claude Code 客户端,发现 Anthropic 用隐写术在中国用户请求里嵌入隐藏标记——读系统时区、比对 147 个加密域名、在日期字符串里替换 Unicode 字符。这段代码静默运行三个月,从未披露。三…

2026/7/7 2:36:12 阅读更多 →

日新闻

鸿蒙新特性:图片画廊与轮播导航——构建沉浸式图片浏览体验

鸿蒙新特性:图片画廊与轮播导航——构建沉浸式图片浏览体验

图片浏览是移动应用中最高频的场景之一。从社交应用的照片流到电商平台的商品图集,从旅游应用的景点相册到摄影作品展示——用户对图片浏览的体验要求不断提高:流畅的切换动画、直观的缩略图导航、便捷的收藏操作、自动播放模式。HarmonyOS NEXT ArkUI 虽…

2026/7/7 0:05:16 阅读更多 →
24V DC-DC降压芯片PW2312B/PW2815,SOT23-6到SOP8-EP方案对比

24V DC-DC降压芯片PW2312B/PW2815,SOT23-6到SOP8-EP方案对比

24V稳压芯片完整选型指南 PW8600 PW75XX PW2815 PW2312B LDODC/DC全方案 一、24V稳压方案概述 24V直流电源在工业自动化、门禁系统、电梯控制、汽车电子、LED驱动、监控设备等场景中应用极广,是最常见的中压直流母线电压。要将24V母线稳定降压至下游MCU、传感器…

2026/7/7 0:05:16 阅读更多 →
RAG+知识图谱混合检索与Graph RAG核心对比

RAG+知识图谱混合检索与Graph RAG核心对比

做企业RAG落地的团队,往往容易卡在一容易踩坑的选型难题: 当需求单纯靠向量RAG搞不定、单纯靠知识图谱也搞不定,必须同时依赖「文本语义理解 实体关系推理」时,到底是做「向量图谱混合检索」就够了,还是必须上「Grap…

2026/7/7 0:07:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/6 8:11:50 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/6 8:11:52 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/6 6:52:56 阅读更多 →

月新闻