基础设施
等待队列
文件描述符fd的等待队列,等待队列上可以挂一个等待项,等待项包含一个对象和设置的回调函数。一般等待对想都是一个线程(进程)。挂上去就睡眠,有数据了内核就挨个调用这些的等待对象的回调函数
线程优先级
硬中断 > 内核任务(包括软中断)> 用户态任务
监工epoll
里面有:
- 一棵红黑树:存放所有被监听的 fd(快速增删查)
- 一个就绪队列:存放已经触发事件的 fd
- 等待队列:正在 epoll_wait 的进程 关键数据结构epoll item epoll item 是文件描述符包装起来的对象,用于插入红黑灰和就绪队列。
epoll 本质是一个专业的监视器。之前线程(进程)遇到io长的要么阻塞到一个fd(自己挂在等待队列等),要么就起一个线程专门去轮训好多fd(cpu高)。现在用epoll,等于雇佣了一个监视器,有需要等待fd就给丢给监视器去监控,自己就只跟epoll打交道,提交完就等着epoll(不消耗cpu又可以看多个)。监视器也没有啥申请的就跟大树的根、神经的一个突触一样,来一个fd需要处理,就包装成一个epoll item注册在自己的红黑树上,然后挂到fd的等待队列上去。等到fd上有数据到了,就逐个唤醒等待队列上的等待对象。epoll item里有epoll本身的地址,所以能找到epoll;epoll item的回调函数是通用的,就根据已有信息把epoll item对应的文件描述符加到epoll的就绪队列里去; 当有数据到来或者要发数据数据时,一般都是中断触发(硬中断、中断上半部分),硬中断只是作标记把唤醒等待队列等事情放到软中断(中断下半部、内核任务队列)后马上恢相应硬中断。 这个时候内核会调度内核任务区执行,这当然包括刚刚创建的软中断(内核任务队列),在内核任务执行的过程中还会有硬中断到来,也就是说会持续创建软中断,直到软中短等内核任务处理完,当然包含唤醒epoll本身的等待队列,才会切换到用户态区执行。所以 这个阶段可能有很多个会被加到就绪队列,然后等待epoll的线程就拿到了一堆有数据的文件描述符。 当然想网卡也可能会批量处理,多个包发一个中断,或者进入短暂的轮训模式,收取所包后再恢复中断模式。
NGINX使用
NGINX架构1个master+多个worker
master只管启动时监听端口80或者443,然后fork出多个完全一样的worker进行实际的业务处理,master本身只做worker的,监控管理(挂掉拉启)、配置文件热加载、信号等,不参与具体业务。 每个worker抖有一个epoll ,所有worker同时监听listening epoll,有连接到来时惊群,拿到互斥锁的才能去accept这个连接,然后把链接加入到自己的epoll里去。