揭开高性能服务器底层面纱
时间:2021-09-03 10:07:59
手机看文章
扫描二维码
随时随地手机看文章
[导读]揭开高性能服务器底层面纱一、前言我们经常听说高性能服务器,那什么是高性能服务器;用大白话来解释就是说处理事件快,效率高,占用服务器资源少,多路复用等等集万千宠爱于一身;但是,往往要想做到高性能,这是非常难的,需要一个好的优秀的架构和底层接口。这篇文章只限于linux平台,对于wi...
揭开高性能服务器底层面纱
一、前言
我们经常听说高性能服务器,那什么是高性能服务器;用大白话来解释就是说处理事件快,效率高,占用服务器资源少,多路复用等等集万千宠爱于一身;但是,往往要想做到高性能,这是非常难的,需要一个好的优秀的架构和底层接口。这篇文章只限于 linux 平台,对于 windows 平台下,可以去参考下 IOCP 的用法,这里就不多说了~目前主流的高性能服务器底层都是封装了 EPOLL 接口,使用 epoll 进行事件处理,为什么 epoll 可以作为高性能服务器底层事件处理?那就让我们从源码下手,来揭开面纱~二、源码解读
两个至关重要的结构体eventpoll结构体:
/*
* 此结构体存储在file->private_data中
*/
/*
eventpoll结构体是epoll的核心里面存放着许多信息,主要包括
1. struct rb_root rbr;这是一颗红黑树的根节点,代表着一颗红黑树,
红黑树下面挂的是我们感兴趣的socket的事件,当我们调用epoll_ctl向
epoll添加感兴趣的socket事件时,系统将我们的传递的信息封装成
struct epitem结构体,然后挂到这颗红黑树的相应节点上
2.struct list_head rdllist;这是一个双向链表,这个双向链表中存放
的是就绪的事件当我们调用epoll_wait的时候这些事件会返回给用户
3.struct file *file;文件结构指针,指向epoll文件
*/
struct eventpoll {
// 自旋锁,在kernel内部用自旋锁加锁,就可以同时多线(进)程对此结构体进行操作
// 主要是保护ready_list
spinlock_t lock;
// 这个互斥锁是为了保证在eventloop使用对应的文件描述符的时候,文件描述符不会被移除掉
struct mutex mtx;
// epoll_wait使用的等待队列,和进程唤醒有关
wait_queue_head_t wq;
// file->poll使用的等待队列,和进程唤醒有关
wait_queue_head_t poll_wait;
// 就绪的描述符队列,双向链表
struct list_head rdllist;
// 通过红黑树来组织当前epoll关注的文件描述符
struct rb_root rbr;
// 在向用户空间传输就绪事件的时候,将同时发生事件的文件描述符链入到这个链表里面
struct epitem *ovflist;
// 对应的user
struct user_struct *user;
// 对应的文件描述符
struct file *file;
// 下面两个是用于环路检测的优化
int visited;
struct list_head visited_list_link;
};
epitem结构体// 对应于一个加入到epoll的文件
struct epitem {
// 挂载到eventpoll 的红黑树节点
struct rb_node rbn;
// 挂载到eventpoll.rdllist 的节点
struct list_head rdllink;
// 连接到ovflist 的指针
struct epitem *next;
/* 文件描述符信息fd file, 红黑树的key */
struct epoll_filefd ffd;
/* Number of active wait queue attached to poll operations */
int nwait;
// 当前文件的等待队列(eppoll_entry)列表
// 同一个文件上可能会监视多种事件,
// 这些事件可能属于不同的wait_queue中
// (取决于对应文件类型的实现),
// 所以需要使用链表
struct list_head pwqlist;
// 当前epitem 的所有者
struct eventpoll *ep;
/* List header used to link this item to the "struct file" items list */
struct list_head fllink;
/* epoll_ctl 传入的用户数据 */
struct epoll_event event;
};
int epoll_create(int size);
作用:调用epoll_create方法创建一个epoll的句柄源码:SYSCALL_DEFINE1(epoll_create, int, size)
{
if (size <= 0)
return -EINVAL;
return do_epoll_create(0);
}
从源码来看,其实 size 这个参数并没有什么作用,只要大于 0 就可以了~我从其他地方获取资料说的是:以前底层实现是哈希表,现在是红黑树,为了兼容所以才保留了这个参数,也不知道真假,权当了解一下~接着看下do_epoll_create
static int do_epoll_create(int flags)
{
int error, fd;
struct eventpoll *ep = NULL;
struct file *file;
/* Check the EPOLL_* constant for consistency. */
BUILD_BUG_ON(EPOLL_CLOEXEC != O_CLOEXEC);
if (flags