nginx是一个事件驱动的框架,这个事件指的是网络事件。
nginx的每一个网络连接会自动的对应两个事件:读事件、写事件。
一、网络事件
图1
请求传输的过程(从主机A到主机B):
-
从主机A的应用层发送一个get请求。
-
在传输层,给请求的报文加上TCP头部,带着源端口合目标端口信息。
-
在网络层,给请求报文加上IP头部,带着源IP和目标IP信息。
-
在链路层,给请求报文加上源MAC地址和目标MAC地址。
-
经过以太网,到达路由器,路由器中有一个路由表(静态路由表、动态路由表),存放着整个网络所有的网络节点,节点之间的路由信息等,请求报文到达路由器之后,找到要发送的路径,然后发送请求报文。
-
请求报文经过广域网,到达目标地点的路由器,进而通过以太网找到目标主机,经过链路层、网络层、传输层、应用层,层层剔除信息,最后发送到主机B的目标程序上。
二、报文
图2
注意:
-
MTU:最大传输单元,即物理层(数据链路层)提供给上层(一般是网络层)最大一次传输数据的大小,每个以太网帧最小是64个字节,最大是1518字节,对于不在该区间大小的数据帧,则被认为是错误帧,会被以太网丢弃。以太网的帧头(14字节)和帧尾(4字节)共占18个字节,所以上层数据帧最大为1500个字节。
-
MSS:传输层概念,TCP每次可以传输的字节数最大值,为了达到最佳传输效率,TCP协议在建立连接时,通常双方会协商MSS值,该值为MTU值减去IP数据包包头(20字节)和TCP数据包包头(20字节),即为1460字节,并取双方最小的值作为MSS。
-
网络事件:每收到一个小于MSS的报文时,就是一个网络事件。
三、接口和事件的关系
图 3
对于nginx来说,接收到请求就是一个读事件,比如get请求,nginx接收到这个请求之后,需要读这个请求,这就是一个读事件,要给客户端返回响应,需要nginx将响应写到操作系统中,由操作系统将响应发送给客户端,这就是一个写事件。
每一类的事件都会绑定一个消费者,也就是用于处理这类事件的方法。
四、事件驱动模型
图 4
-
当nginx刚启动时,是处于wait for events on connections中的,此时nginx的状态是sleep状态,等待新事件进来这一步对应epoll中的epoll wait阻塞方法。
-
当有一个新的请求连接被nginx操作系统处理完之后,nginx操作系统就会通知epoll_wait方法继续向下执行,同时唤醒worker进程。
-
nginx向下执行,向操作系统要事件,KERNEL是操作系统内核,操作系统会将所有的事件放在一个队列A中,比如建立连接,收到一个TCP请求报文等都会放到该事件队列A中。
-
nginx线判断该事件队列A是否为空,不为空则会取出事件进行处理,在处理事件的过程中可能会产生一个新的事件,比如新建立一个请求时,会生成一个定时器事件,或者要给客户端返回响应等,这些事件都会被写进一个事件队列B中。
-
当读事件队列为空时,nginx则又会进入wait for events on connections状态。
注意:
- post数据量虽然很大,但是TCP层会将其切割成多个报文,每个报文最大数据量为MSS,所以处理一个连接的多个报文,消耗的时间是很短的。
- nginx的epoll处理事件是单线程的。