epoll本质原理
second60 20180622
1. epoll简介
epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。
2. epoll优点
1. 支持一个进程打开大数目的socket描述符
(1) 查最大支持描述符: cat /proc/sys/fd/file-max
2. IO效率不随FD数目增加而线性下降
(1) 只对活跃的描述符进行操作(select/poll 全部描述符遍历)
3. 使用mmap加速内核与用户空间的消息传递
(1) 共享内存的方式,避免用户空间和内核空间拷贝的消耗
3 ET和LT模式
LT(level triggered)是缺省的工作方式,并且同时支持block和no-block socket.在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。传统的select/poll都是这种模型的代表。
ET (edge-triggered)是高速工作方式,只支持non-block socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述符不再为就绪状态了(比如,你在发送,接收或者接收请求,或者发送接收的数据少于一定量时导致了一个EWOULDBLOCK 错误)。但是请注意,如果一直不对这个fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知(only once),不过在TCP协议中,ET模式的加速效用仍需要更多的benchmark确认。
4. ET和LT的优缺点
1. ET只触发一次,如果数据一次未读完,需程序循环读取数据,效率好,出错的可能性大
2. LT 只要有数据就一直触发,直到数据处理完成,效率比ET差,出错的可性性小
总结:如果系统
5. 头文件代码
//头文件路径:/usr/include/sys/epoll.h #include <sys/epoll.h> enum EPOLL_EVENTS { EPOLLIN = 0x001, EPOLLPRI = 0x002, EPOLLOUT = 0X004, EPOLLRDNORM = 0x040, EPOLLRDBAND = 0x080, EPOLLWRNORM = 0x100, EPOLLWRBAND = 0x200, EPOLLMSG = 0x400, EPOLLERR = 0x008, EPOLLHUP = 0x010, EPOLLRDHUP = 0x2000, EPOLLWAKEUP = 1u << 29, EPOLLONESHOT = 1u << 30, EPOLLET = 1u << 31, }; #define EPOLL_CTL_ADD 1 #define EPOLL_CTL_DEL 2 #define EPOLL_CTL_MOD 3 typedef union epoll_data { void *ptr; int fd; uint32_t u32; uint64_t u64; } epoll_data_t; struct epoll_event { uint32_t events; epoll_data_t data; } __EPOLL_PACKED; // 创建一个epoll文件描述符 // size是内核保证能够正确处理的最大句柄数,多于这个数内核不保证效果。 int epoll_create(int __size); int epoll_create1(int __flags); // 添加/修改/删除需要侦听的文件描述符及其事件 // 每次添加/修改/删除被侦听的文件描述符都需调epoll_ctl, // 所以尽量少调epoll_ctl,防止其所引来的开销 // 如应用中大量短连接(web服务器),频繁调用,可以成为系统瓶颈 int epoll_ctl(int __epfd, int __op, int __fd,struct epoll_event *_event); // 接收发生在被侦听的描述符上的用户感兴趣的IO事件 int epoll_wait(int __epfd, struct epoll_event *events,int __maxevents, int __timeout); int epoll_pwait(int __epfd, struct epoll_event *events,int __maxevents, int __timeout);
6. EPOLL 本质原理
1. 内核初始化时,epoll向内核注册一个文件系统,同时开辟出epoll的高速cache区。
高速cache区: 就是连续的物理内存页,然后在上建立slab层.
2. epoll_create时,在epoll文件系统中创建一个file结点,同时在高速cache区,创建红黑树和就绪链表。
红黑树: 用来存储外部传来的文件描述符。
就绪链表:用来存储准备就绪的事件。
3. epoll_ctl: 把文件描述符和事件存放到file对象对应的红黑树上,然后给内核中断处理程序注册一个回调函数
告诉内核,如果这个句柄的中断到了,就把它放到准备就绪的list链表中。
4. 当一个socket上有数据了,内核把网卡上的数据copy到内核中后,就把socket放到准备就结的链表中。
5. epoll_wait: 调用时,仅返回就绪链表中的数据,把准备就绪的socket拷贝到用户态内存,并清空就绪列表。上层程序获取有效事件并处理。
ET模式和LT模式,内核处理:
epoll_wait返回后会清空就绪列表
1. ET模式,不用处理,清空后不会再通知
2. LT模式,socket上有未处理事件,又把该句柄加入就绪链表。
7 epoll 处理最大连接数
可查看 /proc/sys/fs/file-max文件, 根据内存而定,1G内存大约10万个,8G内存大约80万人。16G内存大约160万个文件描述符。
但这些要根据系统内存和已使用的文件描述符而定。有人在8G内存的linux系统下测试,可以同时连接70万左右连接。理论上估计16G内存, 可以同时连接100万描述符。
这里说的是一个epoll的连接数,证明了epoll的强大和高效。
8 总结
结合了网上博客总结了epoll的实现原理6中介绍了本质原理,可以画些图来表示。
参考资料
epoll原理
https://baike.baidu.com/item/epoll/10738144?fr=aladdin
slab原理
https://baike.baidu.com/item/slab/5803993?fr=aladdin
epoll详解
http://www.cnblogs.com/ajianbeyourself/p/5859998.html