引言

Redis 是一个单线程却性能非常好的内存数据库, 主要用来作为缓存系统。 Redis 采用网络 I/O 多路复用技术来保证在多个连接时,系统的高吞吐量(TPS)。

系统吞吐量(TPS)指的是系统在单位时间内可处理的事务的数量,是用于衡量系统性能的重要指标。影响系统吞吐量的因素很多,包括并发数和系统资源(CPU、内存、系统I/O操作、外部接口)等,系统资源等这些因素可以用平均响应时间指标来衡量

五种 I/O 模型

要理解 Redis 采用网络 I/O 多路复用技术,就得先了解五种 I/O 模型,如下:

  • 阻塞 I/O 模型

    最传统的一种 I/O 模型,即在读写数据过程中会发生阻塞现象。

    当用户线程发出 I/O 请求之后,内核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会处于阻塞状态(block),用户线程交出 CPU。当数据就绪之后,内核会将数据拷贝到用户线程,并返回结果给用户线程,用户线程才解除阻塞状态。

    举例如下:

    data = socket.read();

    如果数据没有就绪,用户线程就会一直阻塞在 read 方法。

  • 非阻塞 I/O 模型

    当用户线程发起一个 read 操作后,并不需要等待,而是马上就得到了一个结果。如果结果是一个 error 时,它就知道数据还没有准备好,于是它可以再次发送 read 操作。一旦内核中的数据准备好了,并且又再次收到了用户线程的请求,那么它马上就将数据拷贝到了用户线程,然后返回。

    所以事实上,在非阻塞 I/O 模型中,用户线程需要不断地询问内核数据是否就绪,也就说非阻塞 I/O 不会交出 CPU,而会一直占用 CPU,从而导致 CPU 占用率非常高。

  • 多路复用 I/O 模型

    多路复用 I/O 模型是目前使用得比较多的 I/O 模型。

    在多路复用 I/O 模型中,会有一个线程不断去轮询多个 socket 的状态,只有当 socket 真正有读写事件时,才真正调用实际的 I/O 读写操作。因为在多路复用 I/O 模型中,只需要使用一个线程就可以管理多个 socket,系统不需要建立新的进程或者线程,也不必维护这些线程和进程,并且只有在真正有 socket 读写事件进行时,才会使用 I/O 资源,所以它大大减少了资源占用(如 CPU)。

    会思考的你也许会想到,可以采用多线程+ 阻塞 I/O 达到类似的效果,但是由于在多线程 + 阻塞 I/O 中,每个 socket对应一个线程,这样会造成很大的资源占用,并且尤其是对于长连接来说,线程的资源一直不会释放,如果后面陆续有很多连接的话,就会造成性能上的瓶颈。

    而多路复用 I/O 模式,通过一个线程就可以管理多个 socket,只有当 socket 真正有读写事件发生才会占用资源来进行实际的读写操作。因此,多路复用IO比较适合连接数比较多的情况。

    另外,多路复用 I/O 为何比非阻塞 I/O 模型的效率高是因为在非阻塞 I/O 中,不断地询问 socket 状态时通过用户线程去进行的,而在多路复用 I/O 中,轮询每个 socket 状态是内核在进行的,这个效率要比用户线程要高的多。

    值得注意的是,多路复用 I/O 模型是通过轮询的方式来检测是否有事件到达,并且对到达的事件逐一进行响应。因此对于多路复用 I/O 模型来说,一旦事件响应太慢,那么就会导致后续的事件迟迟得不到处理,并且会影响新的事件轮询。

    这就是说,如果 Redis 每条命令执行如果占用大量时间,就会造成其他线程阻塞,对于 Redis 这种高性能服务是致命的,所以 Redis 是面向高速执行的数据库。

  • 信号驱动 I/O 模型

    在信号驱动 I/O 模型中,当用户线程发起一个 I/O 请求操作,会给对应的 socket 注册一个信号函数,然后用户线程会继续执行,当内核数据就绪时会发送一个信号给用户线程,用户线程接收到信号之后,便在信号函数中调用 I/O 读写操作来进行实际的 I/O 请求操作。

    这个一般用于 UDP 中,对 TCP 套接口几乎是没用的,原因是该信号产生得过于频繁,并且该信号的出现并没有告诉我们发生了什么事情。

  • 异步 I/O 模型

    异步 I/O 模型才是最理想的 I/O 模型,在异步 I/O 模型中,当用户线程发起 read 操作之后,立刻就可以开始去做其它的事。而另一方面,从内核的角度,当它收到一个 asynchronous read 之后,它会立刻返回,说明 read 请求已经成功发起了,因此不会对用户线程产生任何阻塞(block)。

    然后,内核会等待数据准备完成,然后将数据拷贝到用户线程,当这一切都完成之后,内核会给用户线程发送一个信号,告诉它 read 操作完成了。

    也就是说,用户线程完全不需要关心实际的整个 I/O 操作是如何进行的,只需要先发起一个请求,当接收内核返回的成功信号时表示 I/O 操作已经完成,可以直接去使用数据了。

这五种 I/O 模型中,前面四种 I/O 模型实际上都属于同步 I/O,只有最后一种是真正的异步 I/O,因为无论是多路复用 I/O模型还是信号驱动 I/O 模型,I/O 操作的第 2 个阶段都会引起用户线程阻塞,也就是内核进行数据拷贝的过程都会让用户线程阻塞。

为何 Redis 要使用 I/O 多路复用技术

现在来回答这个问题就 so easy 啦!

首先,Redis 是单线程架构,所有的命令操作都是先进入队列,然后一个一个按照顺序线性执行的,但是由于读写操作等待用户输入或输出都是阻塞的,所以 I/O 操作在一般情况下往往不能直接返回,这会导致某一文件的 I/O 阻塞导致整个进程无法对其它客户提供服务,而采用 I/O 多路复用技术就是为了解决这个问题。

Redis 为何不采用异步 I/O 模型,这个不是效率更高吗?这玩意儿在多线程下才能发挥功效,而 Redis 是单线程架构哈。

epoll 是什么

epoll 其实只是众多实现 I/O多路复用模型的技术当中的一种而已,但是相比其他 I/O 多路复用技术(select, poll等),epoll有诸多优点(Redis 也支持 select 和 poll,默认使用 epoll)

  1. epoll 没有最大并发连接的限制,上限是最大可以打开文件的数目,这个数字一般远大于 2048,
  2. 效率提升, epoll 最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中, epoll 的效率就会远远高于 select 和 poll
  3. 内存拷贝, epoll 直接使用的 "共享内存",可以跳过传统的内存拷贝操作,效率更高

总结

Redis 采用 I/O 多路复用技术(epoll)是因为 Redis 是单线程架构,是为了避免网络 I/O 读写操作阻塞整个进程。

Redis I/O 多路复用技术原理的更多相关文章

  1. Lind.DDD.RedisClient~对StackExchange.Redis调用者的封装及多路复用技术

    回到目录 两雄争霸 使用StackExchange.Redis的原因是因为它开源,免费,而对于商业化的ServiceStack.Redis,它将一步步被前者取代,开源将是一种趋势,商业化也值得被我们尊 ...

  2. 大数据相关技术原理资料整理(hdfs, spark, hbase, kafka, zookeeper, redis, hive, flink, k8s, OpenTSDB, InfluxDB, yarn)

    hdfs: hdfs官方文档 深入理解HDFS的架构和原理 https://blog.csdn.net/kezhong_wxl/article/details/76573901 HDFS原理解析(总体 ...

  3. Redis单机数据库的实现原理

    本文主要介绍Redis的数据库结构,Redis两种持久化的原理:RDB持久化.AOF持久化,以及Redis事件分类及执行原理.最后,分别介绍了单机班Redid客户端和Redis服务器的使用和实现原理. ...

  4. 液晶常用接口“LVDS、TTL、RSDS、TMDS”技术原理介绍

    液晶常用接口“LVDS.TTL.RSDS.TMDS”技术原理介绍 1:Lvds Low-Voltage Differential Signaling 低压差分信号 1994年由美国国家半导体公司提出之 ...

  5. Oracle体系结构之控制文件的多路复用技术

    在Windows操作系统中,如果注册表文件被损坏了,就会影响操作系统的稳定性.严重的话,会导致操作系统无法正常启动.而控制文件对于Oracle数据库来说,其作用就好象是注册表一样的重要.如果控制文件出 ...

  6. 进阶的Redis之哈希分片原理与集群实战

    前面介绍了<进阶的Redis之数据持久化RDB与AOF>和<进阶的Redis之Sentinel原理及实战>,这次来了解下Redis的集群功能,以及其中哈希分片原理. 集群分片模 ...

  7. I/O多路复用技术(multiplexing)是什么?

    作者:知乎用户链接:https://www.zhihu.com/question/28594409/answer/52763082来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注 ...

  8. 解读I/O多路复用技术

    前言 当我们要编写一个echo服务器程序的时候,需要对用户从标准输入键入的交互命令做出响应.在这种情况下,服务器必须响应两个相互独立的I/O事件:1)网络客户端发起网络连接请求,2)用户在键盘上键入命 ...

  9. Redis | 第5章 Redis 中的持久化技术《Redis设计与实现》

    目录 前言 1. RDB 持久化 1.1 RDB 文件的创建与载入 1.2 自动间隔性保存 1.2.1 设置保存条件 1.2.2 dirty 计数器和 lastsave 属性 1.2.3 检查保存条件 ...

随机推荐

  1. IIS误删了默认网站,恢复方法

    有时候安装好IIS后,会不小心把IIS的默认网站删除.重新去新建可能会出现一些错误例如"提示文件已存在无法执行"等奇怪的错误,下面是具体的默认网站的恢复方法 找到目录C:\wind ...

  2. Windows Service 2016 Datacenter\Stand\Embedded激活方法

    安装好系统后连入互联网之后使用管理员身份打开命令行 输入命令 slmgr /skms kms.03k.org 弹出窗口提示模式修改成功后再输入命令:slmgr /ato 以下为各个版本的key 版本: ...

  3. oo第三单元——社交网络

    第三单元的作业背景是实现一个社交观关系模拟系统,主要训练了JML的阅读和理解能力,和图的一些数据结构和算法. JML语言的理论基础 JML相对于实现代码是比较抽象的,规定了方法的前提副作用结果.数据的 ...

  4. 它来了,它来了,HarmonyOS应用开发在线体验来了

    接下来是我们的两分钟科普,一分钟玩转HarmonyOS应用开发在线体验,一分钟简单了解"一次开发.多设备部署"的原理.萌新的开发者也能第一时间掌握,往下看吧~ 一分钟玩转Harmo ...

  5. xctf - stack2

    xctf - stack2 文件check一下,几乎全开了 运行一下程序,好像很正常呢: 再来一个大的,好像有点儿问题,变1.00了 在ida中查看,在输入的时候没有检查数据大小 可以通过劫持eip获 ...

  6. 8-50.Pow(x,n)

    题目描述: 解题思路: 第一想法是递归,结果f(x,n) = x * f(x,n-1);这种方法的空间复杂度太高了,太想当然. 看了下题解:采取分治的方法:f(x,n) = f(x,n/2) * f( ...

  7. Day16_88_通过反射机制执行方法

    通过反射机制执行方法 * method.invoke(object,"admin","123"); * 代码 import java.lang.reflect. ...

  8. BB网络层测试

    网络层测试2020 问题 1 以下不属于网络层的协议是___A_______. A  DHCP  B ICMP  C IGMP  D ARP 10 分    问题 2 如果目的网络.目的主机都对,但是 ...

  9. 常用head标签

    最小推荐 <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content= ...

  10. Pytorch系列:(四)IO操作

    首先注意pytorch中模型保存有两种格式,pth和pkl,其中,pth是pytorch默认格式,pkl还支持pickle库,不过一般如果没有特殊需求的时候,推荐使用默认pth格式保存 pytorch ...