likes
comments
collection
share

Java 面试系列第二篇 epoll

作者站长头像
站长
· 阅读数 4

Java面试系列第二篇 epoll

要不是为了面试,我可能也不会了解 epoll;本文是为了 epoll 面试而整理的文章。

一、多路复用

epoll 是一种用于处理大量并发连接的 Linux 内核中的多路复用 IO 接口,它是 select/poll 的增强版本。相比于 select,epoll 最大的好处在于它不会随着监听 fd 数目的增长而降低效率,因为在内核中的 select 实现中,它是采用轮询来处理的,轮询的 fd 数目越多,自然耗时越多。

多路复用,是指用一个线程来检查多个文件描述符的就绪状态,一旦就绪,就能够通知程序进行相应的读写操作, select,poll,epoll本质上都是同步 IO。 IO 多路复用技术的最大优势是系统开销小。

不用针对每一个链接都创建进程/线程,从而大大减少了系统的开销

二、select

select 是最早实现 IO 多路复用的技术;通过轮询的方式来管理若干个连接。

处理的大致逻辑:

  • 将需要管理的 socket 连接全部放到一个文件描述符号集合 fds
  • 内核遍历fds,检查 socket 接收缓冲区是否有数据;将此有 socket 数据的标记为可读,把整个 fds 拷贝回用户进程;用户进程再遍历 fds,找到被标记的 fds,然后处理数据。

select 只支持同时管理 1024 个连接。

三、poll

poll 不是用数组来存储文件描述符,而是以链表的形式存储,不会受到 1024 大小的限制。

但还是需要在用户态和内核态之间来回拷贝 fds,同时遍历文件描述符集合来找到可读 socket。

poll 虽然解决了 fds 集合大小 1024 的限制问题,从实现来看。并没有优化大量描述符数组被整体复制于用户态和内核态的地址空间之间, 以及个别描述符就绪触发整体描述符集合的遍历的低效问题

poll 随着监控的 socket 集合的增加性能线性下降,使得 poll 也并不适合用于大并发场景。

四、epoll

epoll 数据结构

epoll 使用起来非常简单,只需要掌握三个函数就可以使用:epoll_create、epoll_ctl 和 epoll_wait。(Linux实现)

  • epoll_create: 函数用于创建一个 epoll 实例
  • epoll_ctl: 函数用于控制 epoll 实例的操作
  • epoll_wait:函数用于等待 epoll 实例中的事件

Java 面试系列第二篇 epoll 图片来源

epoll & select & poll

  • epoll 使用红黑树管理文件描述符,红黑树插入和删除的都是时间复杂度 O(logN),不会随着文件描述符数量增加而改变,复杂度稳定。
  • select/poll 采用数组/链表的形式管理文件描述符,在遍历文件描述符时,时间复杂度会随着文件描述的增加而增加。
  • epoll 将文件描述符添加和检测分离,减少了文件描述符拷贝的消耗
  • select&poll 调用时会将全部监听的 fd 从用户态空间拷贝至内核态空间,并线性扫描一遍找出就绪的 fd 再返回到用户态。 下次需要监听时,又需要把之前已经传递过的文件描述符再读传递进去,增加了拷贝文件的无效消耗,当文件描述很多时,性能瓶颈更加明显。
  • 而 epoll 只需要使用 epoll_ctl 添加一次,后续的检查使用 epoll_wait,减少了文件拷贝的消耗

Java 面试系列第二篇 epoll

与多线程相比,IO多路复用系统开销小,减少了线程切换带来的开销,同时系统也更容易维护

epoll 在 Linux 中的实现

当某一进程调用 epoll_create 方法时,Linux 内核会创建一个 eventpoll 结构体,这个结构体中有两个成员与 epoll 的使用方式密切相关。eventpoll 结构体如下所示:

struct eventpoll{
    ....
    /*红黑树的根节点,这棵树中存储着所有添加到epoll中的需要监控的事件*/
    struct rb_root  rbr;
    /*双链表中则存放着将要通过epoll_wait返回给用户的满足条件的事件*/
    struct list_head rdlist;
    ....
};

在 epoll中,对于每一个事件,都会建立一个 epitem 结构体

struct epitem{
    struct rb_node  rbn;//红黑树节点
    struct list_head    rdllink;//双向链表节点
    struct epoll_filefd  ffd;  //事件句柄信息
    struct eventpoll *ep;    //指向其所属的eventpoll对象
    struct epoll_event event; //期待发生的事件类型
}

Java 面试系列第二篇 epoll

当调用 epoll_wait 检查是否有事件发生时,只需要检查 eventpoll 对象中的 rdlist 双链表中是否有epitem 元素即可。如果 rdlist 不为空,则把发生的事件复制到用户态,同时将事件数量返回给用户.

流程理解

可按照下图顺序来理解整个 epoll 过程,还是比较清晰的。

Java 面试系列第二篇 epoll 图片来源

两种模型触发

  • 边沿触发:edge-triggered (ET)
  • 水平触发:level-triggered (LT)

水平触发(LT): 关注数据,只要读缓冲区不为空,写缓冲区不满,那么 epoll_wait 就会一直返回就绪,水平触发是epoll的默认工作方式。

边缘触发(ET): 关注变化,只要缓冲区的数据有变化,epoll_wait就会返回就绪。

五、其他

知识补充

查看户能注册到epoll实例中的最大文件描述符的数量限制。案例:从一台服务器查看得到信息。

[admin@xxxxx /home/admin/lxxx/bin]
$cat /proc/sys/fs/epoll/max_user_watches
108060446

阅读推荐

资料描述
select,poll、epoll 教程视频讲解,非常详细。可以多多支持这位博主
zhuanlan.zhihu.com/p/367591714IO多路复用——深入浅出理解select、poll、epoll的实现
blog.csdn.net/shenya1314/…高并发网络编程之epoll详解
zhuanlan.zhihu.com/p/64746509如果这篇文章说不清epoll的本质,那就过来掐死我吧
cloud.tencent.com/developer/a…深入揭秘 epoll 是如何实现 IO 多路复用的!
xiaolincoding.com/os/8_networ…I/O 多路复用 select/poll/epoll