epoll本质原理

epoll本质原理

second60 20180622

1. epoll简介

      epollLinux内核为处理大批量文件描述符而作了改进的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 ETLT模式

LTlevel triggered)是缺省的工作方式,并且同时支持blockno-block socket.在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。传统的select/poll都是这种模型的代表。

ET edge-triggered)是高速工作方式,只支持non-block socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述符不再为就绪状态了(比如,你在发送,接收或者接收请求,或者发送接收的数据少于一定量时导致了一个EWOULDBLOCK 错误)。但是请注意,如果一直不对这个fdIO操作(从而导致它再次变成未就绪),内核不会发送更多的通知(only once),不过在TCP协议中,ET模式的加速效用仍需要更多的benchmark确认。

4. ETLT的优缺点

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的强大和高效。

总结

结合了网上博客总结了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


猜你喜欢

转载自blog.csdn.net/second60/article/details/80774247