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

题主是看redis相关书籍碰到了困惑,那就结合redis源码来回答题主这个问题。
redis源码地址:antirez/redis · GitHub

关于I/O多路复用(又被称为“事件驱动”),首先要理解的是,操作系统为你提供了一个功能,当你的某个socket可读或者可写的时候,它可以给你一个通知。这样当配合非阻塞的socket使用时,只有当系统通知我哪个描述符可读了,我才去执行read操作,可以保证每次read都能读到有效数据而不做纯返回-1和EAGAIN的无用功。写操作类似。操作系统的这个功能通过select/poll/epoll/kqueue之类的系统调用函数来使用,这些函数都可以同时监视多个描述符的读写就绪状况,这样,多个描述符的I/O操作都能在一个线程内并发交替地顺序完成,这就叫I/O多路复用,这里的“复用”指的是复用同一个线程。

以select和tcp socket为例,所谓可读事件,具体的说是指以下事件:
1 socket内核接收缓冲区中的可用字节数大于或等于其低水位SO_RCVLOWAT;
2 socket通信的对方关闭了连接,这个时候在缓冲区里有个文件结束符EOF,此时读操作将返回0;
3 监听socket的backlog队列有已经完成三次握手的连接请求,可以调用accept;
4 socket上有未处理的错误,此时可以用getsockopt来读取和清除该错误。

所谓可写事件,则是指:
1 socket的内核发送缓冲区的可用字节数大于或等于其低水位SO_SNDLOWAIT;
2 socket的写端被关闭,继续写会收到SIGPIPE信号;
3 非阻塞模式下,connect返回之后,发起连接成功或失败;
4 socket上有未处理的错误,此时可以用getsockopt来读取和清除该错误。

Linux环境下,Redis数据库服务器大部分时间以单进程单线程模式运行(执行持久化BGSAVE任务时会开启子进程),网络部分属于Reactor模式,同步非阻塞模型,即非阻塞的socket文件描述符号加上监控这些描述符的I/O多路复用机制(在Linux下可以使用select/poll/epoll)。服务器运行时主要关注两大类型事件:文件事件和时间事件。文件事件指的是socket文件描述符的读写就绪情况,时间事件分为一次性定时器和周期性定时器。相比nginx和haproxy内置的高精度高性能定时器,redis的定时器机制并不那么先进复杂,它只用了一个链表来管理时间事件,而且目前链表也没有对各个事件的到点时间进行排序,也就是说,每次都要遍历链表检查每个事件是否需要到点执行。个人猜想是因为redis目前并没有太多的定时事件需要管理,redis以数据库服务器角色运行时,定时任务回调函数只有位于redis/src/redis.c下的serverCron函数,所有的定时任务都在这个函数下执行,也就是说,链表里面其实目前就一个节点元素,所以目前也无需实现高性能定时器。

Redis网络事件驱动模型代码:redis/src/目录下的ae.c, ae.h, ae_epoll.c, ae_evport.c, ae_select.c, ae_kqueue.c , ae_evport.c。其中ae.c/ae.h:头文件里定义了描述文件事件和事件时间的结构体, 即aeFileEvent和aeTimeEvent;事件驱动状态结构体aeEventLoop, 这个结构体只有一个名为eventloop的全局变量在整个服务器进程中;事件就绪回调函数指针aeFileProc和aeTimeProc;以及操作事件驱动模型的各种API(aeCreateEventLoop以及之后全部的函数声明)。ae_epoll.c, ae_select.c, ae_keque.c和ae_evport.c封装了select/epoll/kqueue等系统调用,Linux下当然不支持kqueue和evport。至于究竟选择哪一种I/O多路复用技术,在ae.c里有预处理控制,也就是说,这些源文件只有一个能最后被编译。优先选择epoll或者kqueue(FREEBSD和Mac OSX可用),其次是select。

I/O多路复用技术(multiplexing)是什么?的更多相关文章

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

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

  2. 【计算机网络基础】数据交换技术和多路复用技术的正(nao)确(can)打开方式

    交换的作用   数据交换是计算机网络中两个终端进行数据传输的方式,它又可以分成两种类型:电路交换和分组交换.很显然,问题的核心在于“交换”,那么我们首先要思考的是:交换的作用是什么?   “交换”的作 ...

  3. 【计算机网络】数据交换技术和多路复用技术的正(nao)确(can)打开方式

    交换的作用   数据交换是计算机网络中两个终端进行数据传输的方式,它又可以分成两种类型:电路交换和分组交换.很显然,问题的核心在于“交换”,那么我们首先要思考的是:交换的作用是什么?   “交换”的作 ...

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

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

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

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

  6. Redis I/O 多路复用技术原理

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

  7. IO多路复用技术总结

    来源:微信公众号「编程学习基地」 IO 多路复用概述 I/O 多路复用技术是为了解决进程或线程阻塞到某个 I/O 系统调用而出现的技术,使进程不阻塞于某个特定的 I/O 系统调用. 在IO多路复用技术 ...

  8. 【Http】队头阻塞(Head of line blocking)多路复用(Multiplexing)

        图中第一种请求方式,就是单次发送request请求,收到response后再进行下一次请求,显示是很低效的. 于是http1.1提出了管线化(pipelining)技术,就是如图中第二中请求方 ...

  9. IO多路复用(IO Multiplexing)

    什么是IO多路复用 为什么要有IO多路复用 作者总结 遵循学习新知识的三部曲:是什么?为什么?怎么用? 作者前言:IO多路复用本质上是网络通信过程中的一个技术名词. 什么是IO多路复用 一个用机场管理 ...

随机推荐

  1. zookeeper(五):Zookeeper中的Access Control(ACL)

    概述 传统的文件系统中,ACL分为两个维度,一个是属组,一个是权限,子目录/文件默认继承父目录的ACL.而在Zookeeper中,node的ACL是没有继承关系的,是独立控制的. Zookeeper的 ...

  2. python学习之urlparse()

    urlparse(url, scheme='', allow_fragments=True) <scheme>://<netloc>/<path>;<para ...

  3. Greatest Number 山东省第一届省赛

    Greatest Number Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 Saya likes math, because ...

  4. FileStream常用的属性和方法 (转)

    对流进行操作时要引用 using System.IO; 命名空间 FileStream常用的属性和方法: 属性: CanRead 判断当前流是否支持读取,返回bool值,True表示可以读取 CanW ...

  5. mysql乐观锁和悲观锁

    在多用户环境中,在同一时间可能会有多个用户更新相同的记录,这会产生冲突.这就是著名的并发性问题. 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作. 乐观锁:假设不会发生并发冲突,只在提交 ...

  6. emblog后台拿shell

    emlog版本:5.3.1 先本地弄好shell 新建一个文件夹,里面放shell,shell名称和文件名要一致.压缩为zip 然后在安装插件处上传. 成功后的路径content/plugins/te ...

  7. 如何利用gdb调试程序?

    程序的大体意思就是各一个数组赋值,然后输出来程序已经写在了上面,下面我们就来看一下如何产生带有调试信息的编译文件,这里我们要使用gcc的-g参数,用于在编译文件中加入一些调试信息.发现加了-g和没有加 ...

  8. 页面中添加qq客服

    html页面 <html> <head> <meta http-equiv="Content-Type" content="text/htm ...

  9. 6:7 题一起MySQL数据库分库备份

    企业Shell面试题6:MySQL数据库分表备份 请实现对MySQL数据库进行分表备份,用脚本实现. 解答: [root@db01 scripts]# cat fenbiao.sh #!/bin/ba ...

  10. ARM与X86架构的对决[整编]

    CISC(复杂指令集计算机)和RISC(精简指令集计算机)是当前CPU的两种架构.它们的区别在于不同的CPU设计理念和方法.早期的CPU全部是CISC架构,它的设计目的是  CISC要用最少的机器语言 ...