Redis为什么这么快之IO多路复用
情景复现
面试官:Redis为什么这么快?
我:1. 基于内存 2. 高效数据结构 3. 单线程 4. IO多路复用
面试官:那你讲讲Redis的IO多路复用模型是什么。
我:哦,嗯,啊,呀...IO多路复用、文件描述符、用户态,内核态、哦。
前置内容
Scoket
来源:http://www.cs.cmu.edu/afs/cs/academic/class/15213-f15/www/schedule.html
FD
内核对应已打开文件的索引
IO模型
阻塞IO、非阻塞IO、IO多路复用、信号驱动模型、异步IO
可以看看我的另一篇笔记:https://www.cnblogs.com/handsometaoa/p/17379850.html
Redis的IO多路复用模型是什么
I/O多路复用模型是什么?就是很多网络连接(多路),共(复)用少数几个(甚至是一个)线程。(来源:I/O多路复用技术(multiplexing)是什么?)
Redis采用I/O多路复用机制,使得Redis在单线程模式下依然可以高效的处理多个I/O流。
其核心思想是,先通过 select
/ poll
/ epoll
等系统调用查询监听的文件描述符是否准备就绪,这个操作可阻塞也可立即返回(具体看参数和对应规则),当其中一个或者多个文件描述符IO事件准备就绪才开始下一步,即 read
或者 write
等系统调用,这里才是真正的读或者写。(来源:redis 的 IO 多路复用如何?)
首先Redis IO多路复用采用 epoll
的实现方案,但是在了解 epoll
前先了解一下 select
与 poll
,对后面理解更有帮助。
select
- 一个客户端与服务端连接时,会生成对应一个套接字描述符(fd)
- 进程会将fd加入进程维护的fd列表中,每次调用
select
都需要将 fd列表从用户态进程拷贝到内核,(当fd列表较大时,拷贝开销不可忽略,所以限制其大小为1024) - 内核轮询fd列表,当无fd就绪时,进程阻塞。
- 当网络数据到达内核缓冲区时,网卡发出中断信号通知CPU,CPU收到中断信号,执行对应中断程序
- 中断程序将内核缓冲数据拷贝到对应文件描述符的接收缓冲区
- socket接收数据完毕后,中断程序将进程重新添加至工作队列,并将进程从等待队列中移除
- 进程重新进入工作队列,从阻塞处继续执行。
poll
- 创建pollfd数组,向其中添加关注的fd信息,数组大小自定义
- 调用poll函数,将pollfd数组拷贝到内核空间,转链表存储,无上限
- 内核遍历fd,判断是否就绪
- 数据就绪或超时后,拷贝pollfd数组到用户空间,返回就绪fd数量n
- 用户进程判断n是否大于0
- 大于0则遍历pollfd数组,找到就绪的fd
select与poll原理类似,结合一起看。
epoll
/**
* @param size epoll 要监听文件描述符个数
* @return 返回创建eventpoll对象文件描述符
*/
int epoll_create(int size);
/**
* 事件注册
* @param epdf epoll_create()返回的文件描述符
* @param op 操作类型 1.新增 2.删除 3.更新
* @param fd 本次要操作文件描述符
* @param epoll_event 需要监听的事件:读事件、写事件
* @return 调用成功返回0,不成功返回-1
*/
int epoll_ctl(int epdf,int op,int fd,struct epoll_event *event );
/**
* 获取就绪事件
* @param epdf epoll_create()返回的文件描述符
* @param events 回传就绪事件
* @param maxevents 每次能处理最大事件数
* @param timeout 等待IO事件发生的超时时间 -1 阻塞 0 非阻塞
* @return 大于0 已就绪文件描述符数
*/
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
- 应用程序通过epoll_create系统调用创建一个epoll实例,得到一个文件描述符,用于后续的操作。
- 应用程序使用epoll_ctl系统调用将需要监听的文件描述符(socket、文件等)添加到epoll实例中,并关联相应的事件(读、写、异常)。
- 当应用程序调用epoll_wait系统调用时,操作系统会阻塞程序,等待任何一个注册的事件就绪。
- 当有事件就绪时,epoll_wait会返回,告诉应用程序哪些事件已经就绪。
- 应用程序可以通过遍历返回的事件列表,检查哪些事件已经就绪。
- 应用程序可以对就绪的事件进行处理,如读取数据、写入数据等。
- 应用程序可以再次调用epoll_wait来等待下一轮的事件就绪。
视频推荐:小白也看得懂的 I/O 多路复用解析(超详细案例)
推荐内容
本文来自博客园,作者:帅气的涛啊,转载请注明原文链接:https://www.cnblogs.com/handsometaoa/p/17540321.html