epoll原理剖析:epoll原理剖析以及reactor模型应用
redis源码分析:redis源码分析及driver现实
Nginx模块开发:Nginx源码从模块开发入手,3个项目弄透nginx模块开发
【Redis,Netty,Nginx 等实现高性能IO的核心原理】
I/O
输入输出(input/output)的对象可以是文件(file), 网络(socket),进程之间的管道(pipe)。在linux系统中,都用文件描述符(fd)来表示。
I/O 多路复用(multiplexing)
I/O 多路复用的本质,是通过一种机制(系统内核缓冲I/O数据),让单个进程可以监视多个文件描述符,一旦某个描述符就绪(一般是读就绪或写就绪),能够通知程序进行相应的读写操作。
select、poll 和 epoll 都是 Linux API 提供的 IO 复用方式。
Linux中提供的epoll相关函数如下:
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
Unix五种IO模型
我们在进行编程开发的时候,经常会涉及到同步,异步,阻塞,非阻塞,IO多路复用等概念,这里简单总结一下。
Unix网络编程中的五种IO模型:
Blocking IO - 阻塞IO
NoneBlocking IO - 非阻塞IO
IO multiplexing - IO多路复用
signal driven IO - 信号驱动IO
asynchronous IO - 异步IO
对于一个network IO,它会涉及到两个系统对象:
- Application 调用这个IO的进程
- kernel 系统内核
那他们经历的两个交互过程是:
阶段1: wait for data 等待数据准备;
阶段2: copy data from kernel to user 将数据从内核拷贝到用户进程中。
之所以会有同步、异步、阻塞和非阻塞这几种说法就是根据程序在这两个阶段的处理方式不同而产生的。
事件
可读事件,当文件描述符关联的内核读缓冲区可读,则触发可读事件。
(可读:内核缓冲区非空,有数据可以读取)
可写事件,当文件描述符关联的内核写缓冲区可写,则触发可写事件。
(可写:内核缓冲区不满,有空闲空间可以写入)
通知机制
通知机制,就是当事件发生的时候,则主动通知。通知机制的反面,就是轮询机制。
epoll 的通俗解释
结合以上三条,epoll的通俗解释是:
当文件描述符的内核缓冲区非空的时候,发出可读信号进行通知,当写缓冲区不满的时候,发出可写信号通知的机制。
epoll 数据结构 + 算法
epoll 的核心数据结构是:1个红黑树和1个链表。还有3个核心API。如下图所示:
就绪列表的数据结构
就绪列表引用着就绪的socket,所以它应能够快速的插入数据。
程序可能随时调用epoll_ctl添加监视socket,也可能随时删除。当删除时,若该socket已经存放在就绪列表中,它也应该被移除。(事实上,每个epoll_item既是红黑树节点,也是链表节点,删除红黑树节点,自然删除了链表节点)
所以就绪列表应是一种能够快速插入和删除的数据结构。双向链表就是这样一种数据结构,epoll使用双向链表来实现就绪队列(对应上图的rdllist)。