IO多路复用
基本概念
IO多路复用指用一个线程来处理多个客户端请求 Epoll是一种IO事件通知机制 IO输入输出对象可以是 文件,网络,管道等用文件描述符fd表示的 事件Event分为可读事件和可写事件,有两种触发机制(水平触发和边缘触发) 水平触发机制:只要fd关联的内核缓冲区非空/非满,数据就可以一直读/写,就可以一直发出可读/可写信号进行通知
Epoll Api接口介绍
注:下列Api都是在用户态进行调用 epoll_create会创建epoll实例,会创建红黑树结构和双向链表结构的ReadList epoll_ctl会添加,修改,删除 注册到epoll中的fd对应的事件Event epoll_wait系统调用阻塞等待事件发生,返回给用户态 回调函数处理后的就绪队列的文件描述符列表
协议栈回调
协议栈解析数据后会触发回调函数进行回调,IP头可以解析出源IP和目的IP以及协议,Tcp头可以解析出源端口和目的端口,一个Socket fd就是由一个五元组表示的,除了传入fd之外还会传入事件 回调函数作用: (1)通过fd找到对应节点 (2)把节点加入就绪队列
Epoll优点
(1)Epoll使用了事件就绪通知,避免线性轮询所有fd文件描述符,避免不必要开销 (2)可以有效处理大量并发连接 (3)Epoll_wait只返回给用户态就绪的文件描述符列表,减少不必要的事件处理 (4)支持边缘触发机制,减少数据从内核到用户空间的拷贝次数
Epoll在Linux内核中的实现方式
(1)红黑树:存储注册的文件描述符FD,在添加删除查找fd的时候时间复杂度都是O(logn),是一种自平衡的二叉搜索树 (2)就绪队列ReadList:内核维护一个双向链表,包含已就绪的文件描述符,当文件描述符就绪时会被添加到链表中,程序可以通过系统调用获取链表中存储的就绪事件,避免轮询所有文件描述符,采用双向链表的原因是因为双向链表的插入和删除时间复杂度都是O(1) (3)红黑树的有序性保证了事件触发顺序与节点在红黑树中的顺序一致,当多个时间同时准备就绪时,epoll会按照红黑节点的顺序依次触发事件
Nginx中的Epoll和惊群现象
Nginx采用的Epoll IO多路复用机制,每个Worker进程都会通过epoll_create创建单独的Epoll实例,共享监听套接字,由操作系统来分配每个连接的文件描述符fd注册到worker的Epoll实例中。 Epoll惊群现象为一个新的连接到达监听套接字时,多个Epoll都争抢将连接注册到自己的Epoll,最终只能由一个Epoll能够accept处理,其他的进程就白唤醒了,这就导致了系统资源的浪费 (1)Accept Mutex 锁机制决定哪个 worker 进程接受新的连接,使得只有拿到自旋锁的worker进程可以处理这个连接请求 (2)SO_reuserport采用端口复用的形式,每一个进程都通过监听自己的Socket端口去避免惊群现象
Epoll与poll/Select
Poll每次调用都会将用户态的文件描述符集合拷贝到内核态进行检测,再从内核态拷贝到用户态(用户态管理文件描述符集合) Epoll会将新的IO事件的fd注册到Epoll红黑树实例中,Epoll_wait阻塞等待,数据到达或其他操作触发协议栈回调的时候才将fd对应的节点放入就绪队列中(内核态维护文件描述集合),Epoll_wait才将文件描述符列表发送给用户 所谓加入就绪队列:就是将节点的前后指针联系到一起,红黑树上的原节点也不会delete掉
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库