无疑,在nginx的核心服务中,http服务占据了相当大的份量。那么,要想多了解nginx多一点,则必须要了解其http模块的工作机制。
而在上一篇文章中,我们已完全了解了nginx的worker工作机制,以及它是如何接入http服务的,但很明显那很粗,我们需要更深入点理解http模块的工作原理。
而本身nginx对模块的支持又是复杂的,至少我们认为有两个大方向,正向代理和反向代理。正向代理实际上就是一个http服务器,明显简单些,所以,我们本篇就来说说nginx的正向代理实现吧。
0. 整体时序图
如果你对nginx的http模块工作原理有过深入理解,相信只需要这一张时序图就够。为了节省大家宝贵时,可以先一览宏图。
1.异步io事件的交接
我们知道,nginx的核心是事件io机制的使用,当外部网络io就绪时,内核会回应nginx, 而nginx则会通过accept(), receive(), fd_set 等方法,将事件接入进来,从而转交到http服务模块。其中select模块我们上一篇中已经讲过,此时再简单回顾下:(需要的话)
反正大概意思就是会调用内核级别的select/poll或epoll等io机制,等待io事件的发生,然后返回到用户态。当然,为了保证系统例外情况,都会进行超时设置,避免系统事件检测的偶发异常,可以在超时机制帮助下正常工作。
此处接收到的事件可能写入两个队列: 即是否是 accept 队列之分。最开始建立连接时,自然是放入accept队列的,后续则一般放ngx_posted_events队列中。这两个队列,后续将被分开处理。accept 队列会将socket接入,并注册read监听。而 posted_events 则是需要进行正式处理的队列,将会读取数据,写入客户端等更多工作。
经过 ngx_http_init_connection 之后,就注册了read事件, 该事件基本已就绪, 所以将会在下一次进行select操作时返回该事件, 即下一次worker巡检时触发 read. 而此时的handler则被设置为 ngx_http_wait_request_handler.
ngx_http_wait_request_handler 非常重要的一个任务就是接收客户端的传送数据,即调用 recv 方法处理数据, 使用缓冲区的方式进行读取, 默认缓冲区大小为 1024, 即实际是处理不了太多数据的. 最多读取1024字节, 然后正常情况下就进入到 ngx_http_process_request_line() 逻辑了. 也就是说, 剩下的数据会在接下再被读取, 而非一次性被读取完成. 其中, ngx_http_create_request 主要是为 body体分配内存空间.
而接下来的handler被设置为了 ngx_http_process_request_line , 则会进一步读取数据, 处理事件, 也是处理的核心任务.
2. 核心数据读取解析
前面我们看到, nginx 通过调用系统级recv() 接收部分客户端数据过来, 但那里仅有一个缓冲区的大小, 有可能取到的数据是不完整的. 那么, 自然需要进一步处理, 即: ngx_http_process_request_line . 它会在第一次接到数据时就进行调用, 但如果存在多数据段, 则会反复进行该 handler 的调用(这是一个核心的异步io的处理实现, 类似断点续传):
以上是整个http的主要流程之一, 主要分为读取 header 处理header, 读取body处理body, 最后 ngx_http_run_posted_requests, 做后置处理. 其中重要的实现方式是, 依次读取每个字节, 进行http协议解析, 按行划分 header, 以及读取部分buffer就处理部分header等优化.
接下来, 我们看看其对 body 部分的处理:
大体就是如何使用 recv() 读取数据的过程, 看着流程多, 但实际上其时间复杂度基本为 O(1), 所以效率蛮高的.
3. http 请求的处理
经过数据准备, 数据解析后, 就可以进行逻辑处理了. ngx 中支持许多的功能操作, 如配置内容跳转, 反向代理, 负载均衡 等等. 这些都统一归为一类操作.
可以看出,nginx处理http流程框架非常简单,即一直遍历执行所有checker,但本身checker数量又比较多,所以给我们的处理带来了复杂度。此处相当于是责任链模式的应用,而且这链是可以被任意注册的,所以也为我们扩展性打开了方便之门。从部分上按一定序执行checker,只要有一个处理完成,即带调用后续checker。
这些checker大体上被分为了几类,body数据读取类,config配置文件读取类,rewrite路径重写类,access权限验证类,content内容处理类,log日志记录类。从总体上是有序的,但对于某类处理,则是任意的。
本文讲解了nginx作为正向代理(http服务器)的处理过程,当然我们可以简单认为是一个文件路径查找的过程。无非就是解析请求头请求体信息,然后查找所有可能的地方,验证可能的权限,然后就输出内容到客户端了。其实和其他的http服务器没啥差别,但nginx的优势在于性能,在于配置的简便性。性能上基于非阻塞io,配置上则已形成自有的一套简洁语法。
领取专属 10元无门槛券
私享最新 技术干货