Epoll学习笔记

  • Post author:
  • Post category:其他




Epoll性能特点





Select



Poll



Epoll



Kqueue

几种I/O多路复用做测试(限制100个活动连接,并且每一个连接会有1000次写入)



下图是 libevent(一个知名的异步事件处理软件库)对这几个 I/O 多路复用技术做的性能测试。

在这里插入图片描述



实验结果





fd

数量<1000时,这几种

I/O复用

的性能相互接近,当随着

fd

的数量越来越多,

EPOLL



Kqueue

的相应时间相接近,并且远小

Select



Poll

的响应时间



实验分析



通过实验结果,可以看出

Epoll

在面对大量连接时性能表现优异。



但是,不是任何时候,

Epoll

面对大量连接时都能够有如此表现,上述实验有个很重要的限制条件,

100 Active Connections

,也就是说,假设

Epoll

应对大量fd(15000个),此时其中只有100个活跃连接,

Epoll

才会明显优于其他I/O复用。



如果当活跃连接也为15000个时,

Epoll

将会和Select以及

Poll

性能相近。



在谈Epoll原理之前,先看几个问题(无需知道为什么),并且通过下面的原理解读来理解这些问题




Q: 为什么会出现

I/O多路复用




A: 为了减少进程上下文切换带来的开销。




Q: 是Linux已发行就有

Epoll

了吗?



A:



I/O多路复用是一种技术,而

Select



Poll



Epoll

是实现了该技术的框架。



框架的api发布的时间线:

  • 1983,socket 发布在 Unix(4.2 BSD)
  • 1983,select 发布在 Unix(4.2 BSD)
  • 1994,Linux的1.0,已经支持socket和select
  • 1997,poll 发布在 Linux 2.1.23
  • 2002,epoll发布在 Linux 2.5.44



这些框架的出现是以不断改进的方式向前推进的:

Select

->

Poll

->

Epoll



Poll

是在

Select

的基础上改进,

Epoll



Poll

的基础上改进,可以这么说,

Epoll

是在

I/O多路复用框架

不断发展的结果。




Q:

Epoll

解决了什么问题?



A:

Epoll

优化了

内核



监视进程



监视fd的进程

)的

交互





1

Epoll

原理



1.1 阻塞




Epoll

为什么是阻塞的,这是因为内核收发网络数据的底层机制导致的,并且,阻塞才是高效的方式。



接收网络数据的过程:

在这里插入图片描述



网卡接收数据依赖发送方和传输路径,延迟是毫秒(ms)级别的,相对于用户进程处理数据的纳秒级来说相对很慢,所以用户态的用户进程在等待数据的过程中CPU空闲,此时通过阻塞该进程来让出CPU资源(阻塞不占用CPU资源),提高CPU的利用率。




1.2 阻塞恢复



问题来了,当用户进程阻塞等待数据,数据接受完毕后怎么办



Sokcet结构体包含两个数据:

进程ID

(调用send,read,connect的进程)and

端口号



当数据从网卡到内核时,内核通过

端口号

来确定对应的Sokcet



当数据从内核到用户进程时,内核通过

进程ID

来确定目标进程,然后修改目标进程的状态,从

阻塞状态

变为

可执行状态

,最后通过OS的进程调度,该进程得以从

可执行状态

变为

运行状态

,最终用户的数据得以处理完毕




1.3 过程优化




进程

接收数据的过程存在两处可能造成频繁上下文切换产生大量不必要开销



1.如果频繁接收到

Packet

,那么网卡会频繁发出IRQ,此时,CPU不一定在内核态,有可能在用户态,因此可能会造成大量的内核态与用户态之间频繁的切换



2.

one socket - one proccess

,当一个

Sokcet

处理完,就一定伴随着进程间调度,存在进程间的上下文切换



解决办法:缓冲区的思想



解决问题1:通过网卡驱动中的一种机制

NAPI

机制,这里有兴趣的小伙伴可以自己去了解了解,这里不展开赘述,我直接总结一下:就是

批量收发数据

减少内核态与用户态的切换次数



解决问题2:你肯定已经想到了,解决进程间调度的办法也是

批量收发数据

呗,问题就在于怎样去操作。网卡可以通过

NAPI

机制,内核可以通过大名鼎鼎的

I/O多路复用技术

来优化。就是

n Socket - one proccess

,说白了就是





Socket


复用



一个进程

中。




1.4 EPOLL存储fd数据结构



1.由两个结构体组成,

总集



就绪队列



2.数据结构:1.

红黑树

存储总集

fd

,2

链表

存储就绪

fd




1.5 Epoll与Select、Poll之间的比较



1.提高了总集大小:

fd

数量上限是系统最大可以打开的文件数目(主机内存限制)



2.采用通知机制:每个

fd

上有

callback

函数,只有活跃的

Socket

才会调用

callback

函数



3. 提高了活跃Socket的查找效率:由于通过

epoll_wait

直接获取到的就是活跃Socket,所以用户进程查找时间复杂度为

O(活跃连接数量*logn)

,而

Poll和Select

需要线性查找时间复杂度

O(活跃连接数量*n)



若当活跃连接数量远小于总量n时,Epoll时间复杂度可看作

O(logn)



Poll和Select

时间复杂度可看作

O(n)

,此时Epoll性能优!



若当活跃连接与n相近时,则

Epoll

时间复杂度为

O(nlogn)



Poll和Select

时间复杂度可看作

O(n^2)

,性能相差不大,甚至在某些

业务场景



Epoll

性能还不如

Poll和Select

,所以

Epoll

并不是所谓的万金油,要具体问题具体分析



3.数据处理问题:内核和用户通过

mmap

共享内存,避免内存拷贝(据说不同的linux版本,

Epoll

不用

mmap

,这个以后通过实践考证)



版权声明:本文为qq_27277041原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。