Epoll 到底是什么?“不” 简单的网络I/O模型?

魏小言
云原生领域优质创作者
博客专家认证
2022-04-13 11:41:15

目录

1 简介

2 引言

3 初识 epoll

4 epoll背后的原理

4.1 阻塞

4.2 上下文切换的优化

4.3 IO 多路复用的进化

5 总结

Epoll 到底是什么?“不” 简单的网络I/O模型?
1 简介
Epoll 是个很老的知识点,是后端工程师的经典必修课。这种知识具备的特点就是研究的人多,所以研究的趋势就会越来越深。当然分享的人也多,由于分享者水平参差不齐,也产生的大量错误理解。

今天我再次分享 epoll,肯定不会列个表格,对比一下差异,那就太无聊了。我将从线程阻塞的原理,中断优化,网卡处理数据过程出发,深入的介绍 epoll 背后的原理。相信无论你是否已经熟悉 epoll,本文都会对你有价值。

2 引言
正文开始前,先问大家几个问题。

1、epoll 性能到底有多高。很多文章介绍 epoll 可以轻松处理几十万个连接。而传统 IO 只能处理几百个连接 是不是说 epoll 的性能就是传统 IO 的千倍呢?

2、很多文章把网络 IO 划分为阻塞,非阻塞,同步,异步。并表示:非阻塞的性能比阻塞性能好,异步的性能比同步性能好。

如果说阻塞导致性能低,那传统 IO 为什么要阻塞呢?

epoll 是否需要阻塞呢?

Java 的 NIO 和 AIO 底层都是 epoll 实现的,这又怎么理解同步和异步的区别?

3、都是 IO 多路复用。

既生瑜何生亮,为什么会有 select,poll 和 epoll 呢?

为什么 epoll 比 select 性能高?

PS:

本文共包含三大部分:初识 epoll、epoll 背后的原理 、Diss 环节。

本文的重点是介绍原理,建议读者的关注点尽量放在:“为什么”。

Linux 下进程和线程的区别其实并不大,尤其是在讨论原理和性能问题时,因此本文中“进程”和“线程”两个词是混用的。

关注我 code 杂坛,了解更多......

3 初识 epoll
epoll 是 Linux 内核的可扩展 I/O 事件通知机制,其最大的特点就是性能优异。下图是 libevent(一个知名的异步事件处理软件库)对 select,poll,epoll ,kqueue 这几个 I/O 多路复用技术做的性能测试。

很多文章在描述 epoll 性能时都引用了这个基准测试,但少有文章能够清晰的解释这个测试结果。

这是一个限制了100个活跃连接的基准测试,每个连接发生1000次读写操作为止。纵轴是请求的响应时间,横轴是持有的 socket 句柄数量。随着句柄数量的增加,epoll 和 kqueue 响应时间几乎无变化,而 poll 和 select 的响应时间却增长了非常多。

可以看出来,epoll 性能是很高的,并且随着监听的文件描述符的增加,epoll 的优势更加明显。

不过,这里限制的100个连接很重要。epoll 在应对大量网络连接时,只有活跃连接很少的情况下才能表现的性能优异。换句话说,epoll 在处理大量非活跃的连接时性能才会表现的优异。如果15000个 socket 都是活跃的,epoll 和 select 其实差不了太多。

为什么 epoll 的高性能有这样的局限性?

问题好像越来越多了,看来我们需要更深入的研究了。

 关注我 code 杂坛,了解更多......

4 epoll背后的原理
4.1 阻塞
4.1.1 为什么阻塞

我们以网卡接收数据举例,回顾一下之前我分享过的网卡接收数据的过程。

为了方便理解,我尽量简化技术细节,可以把接收数据的过程分为4步:

NIC(网卡) 接收到数据,通过 DMA 方式写入内存(Ring Buffer 和 sk_buff)。

NIC 发出中断请求(IRQ),告诉内核有新的数据过来了。

Linux 内核响应中断,系统切换为内核态,处理 Interrupt Handler,从RingBuffer 拿出一个 Packet, 并处理协议栈,填充 Socket 并交给用户进程。

系统切换为用户态,用户进程处理数据内容。

网卡何时接收到数据是依赖发送方和传输路径的,这个延迟通常都很高,是毫秒(ms)级别的。而应用程序处理数据是纳秒(ns)级别的。也就是说整个过程中,内核态等待数据,处理协议栈是个相对很慢的过程。这么长的时间里,用户态的进程是无事可做的,因此用到了“阻塞(挂起)”。

4.1.2 阻塞不占用 cpu

阻塞是进程调度的关键一环,指的是进程在等待某事件发生之前的等待状态。请看下表,在 Linux 中,进程状态大致有7种(在 include/linux/sched.h 中有更多状态):

从说明中其实就可以发现,“可运行状态”会占用 CPU 资源,另外创建和销毁进程也需要占用 CPU 资源(内核)。重点是,当进程被"阻塞/挂起"时,是不会占用 CPU 资源的。

换个角度来讲。为了支持多任务,Linux 实现了进程调度的功能(CPU 时间片的调度)。而这个时间片的切换,只会在“可运行状态”的进程间进行。因此“阻塞/挂起”的进程是不占用 CPU 资源的。

另外讲个知识点,为了方便时间片的调度,所有“可运行状态”状态的进程,会组成一个队列,就叫“工作队列”。

4.1.3 阻塞的恢复
————————————————
版权声明:本文为CSDN博主「魏小言」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_34417408/article/details/124142520

...全文
338 1 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
CSDN-Ada助手 2023-01-13
  • 打赏
  • 举报
回复
您可以前往 CSDN问答-运维 发布问题, 以便更快地解决您的疑问

16

社区成员

发帖
与我相关
我的任务
社区描述
code杂坛:提供初级同学进阶的深度与广度!关注一线 “ 互联网时讯、各技术栈、开源产品、面试技巧......“ 等最新动态
云原生架构设计模式 个人社区
社区管理员
  • 魏小言
  • flybirding10011
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

hi,欢迎加入 “code杂坛” 社区!

code杂坛:提供初级同学进阶的深度与广度!关注一线 “ 互联网时讯、各技术栈、开源产品、面试技巧......“ 等最新动态

在这里你可以:

  • 学习最新大厂技术知识
  • 掌握技能进阶各种技巧
  • 交到志同道合的朋友
  • 获取最新图书资讯
  • 参与活动免费赠书
  • 与我们的作者、译者互动!

 

加入我们成为 code杂坛 的同学

【欢迎联系】

微信公众号:code杂坛

试试用AI创作助手写篇文章吧