您当前的位置:首页 > 电脑百科 > 站长技术 > 服务器

Nginx 过滤模块的分析

时间:2019-09-16 13:31:28  来源:  作者:
Nginx 过滤模块的分析

 

过滤模块的分析

相关结构体

ngx_chain_t 结构非常简单,是一个单向链表:

 typedef struct ngx_chain_s ngx_chain_t;
 struct ngx_chain_s {
 ngx_buf_t *buf;
 ngx_chain_t *next;
 };

在过滤模块中,所有输出的内容都是通过一条单向链表所组成。这种单向链表的设计,正好应和了 Nginx 流式的输出模式。每次 Nginx 都是读到一部分的内容,就放到链表,然后输出出去。这种设计的好处是简单,非阻塞,但是相应的问题就是跨链表的内容操作非常麻烦,如果需要跨链表,很多时候都只能缓存链表的内容。

单链表负载的就是 ngx_buf_t,这个结构体使用非常广泛,先让我们看下该结构体的代码:

 struct ngx_buf_s {
 u_char *pos; /* 当前buffer真实内容的起始位置 */
 u_char *last; /* 当前buffer真实内容的结束位置 */
 off_t file_pos; /* 在文件中真实内容的起始位置 */
 off_t file_last; /* 在文件中真实内容的结束位置 */
 u_char *start; /* buffer内存的开始分配的位置 */
 u_char *end; /* buffer内存的结束分配的位置 */
 ngx_buf_tag_t tag; /* buffer属于哪个模块的标志 */
 ngx_file_t *file; /* buffer所引用的文件 */
 /* 用来引用替换过后的buffer,以便当所有buffer输出以后,
 * 这个影子buffer可以被释放。
 */
 ngx_buf_t *shadow; 
 /* the buf's content could be changed */
 unsigned temporary:1;
 /*
 * the buf's content is in a memory cache or in a read only memory
 * and must not be changed
 */
 unsigned memory:1;
 /* the buf's content is mmap()ed and must not be changed */
 unsigned mmap:1;
 unsigned recycled:1; /* 内存可以被输出并回收 */
 unsigned in_file:1; /* buffer的内容在文件中 */
 /* 马上全部输出buffer的内容, gzip模块里面用得比较多 */
 unsigned flush:1;
 /* 基本上是一段输出链的最后一个buffer带的标志,标示可以输出,
 * 有些零长度的buffer也可以置该标志
 */
 unsigned sync:1;
 /* 所有请求里面最后一块buffer,包含子请求 */
 unsigned last_buf:1;
 /* 当前请求输出链的最后一块buffer */
 unsigned last_in_chain:1;
 /* shadow链里面的最后buffer,可以释放buffer了 */
 unsigned last_shadow:1;
 /* 是否是暂存文件 */
 unsigned temp_file:1;
 /* 统计用,表示使用次数 */
 /* STUB */ int num;
 };

一般 buffer 结构体可以表示一块内存,内存的起始和结束地址分别用 start 和 end 表示,pos 和 last 表示实际的内容。如果内容已经处理过了,pos 的位置就可以往后移动。如果读取到新的内容,last 的位置就会往后移动。所以 buffer 可以在多次调用过程中使用。如果 last 等于 end,就说明这块内存已经用完了。如果 pos 等于 last,说明内存已经处理完了。下面是一个简单的示意图,说明 buffer 中指针的用法:

Nginx 过滤模块的分析

 

响应头过滤函数

响应头过滤函数主要的用处就是处理 HTTP 响应的头,可以根据实际情况对于响应头进行修改或者添加删除。响应头过滤函数先于响应体过滤函数,而且只调用一次,所以一般可作过滤模块的初始化工作。

响应头过滤函数的入口只有一个:

 ngx_int_t
 ngx_http_send_header(ngx_http_request_t *r)
 {
 ...
 return ngx_http_top_header_filter(r);
 }

该函数向客户端发送回复的时候调用,然后按前一节所述的执行顺序。该函数的返回值一般是 NGX_OK,NGX_ERROR 和 NGX_AGAIN,分别表示处理成功,失败和未完成。

你可以把 HTTP 响应头的存储方式想象成一个 hash 表,在 Nginx 内部可以很方便地查找和修改各个响应头部,ngx_http_header_filter_module 过滤模块把所有的 HTTP 头组合成一个完整的 buffer,最终 ngx_http_write_filter_module 过滤模块把 buffer 输出。

按照前一节过滤模块的顺序,依次讲解如下:

Nginx 过滤模块的分析

 

响应体过滤函数

响应体过滤函数是过滤响应主体的函数。ngx_http_top_body_filter 这个函数每个请求可能会被执行多次,它的入口函数是 ngx_http_output_filter,比如:

 ngx_int_t
 ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in)
 {
 ngx_int_t rc;
 ngx_connection_t *c;
 c = r->connection;
 rc = ngx_http_top_body_filter(r, in);
 if (rc == NGX_ERROR) {
 /* NGX_ERROR may be returned by any filter */
 c->error = 1;
 }
 return rc;
 }

ngx_http_output_filter 可以被一般的静态处理模块调用,也有可能是在 upstream 模块里面被调用,对于整个请求的处理阶段来说,他们处于的用处都是一样的,就是把响应内容过滤,然后发给客户端。

具体模块的响应体过滤函数的格式类似这样:

 static int 
 ngx_http_example_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
 {
 ...
 return ngx_http_next_body_filter(r, in);
 }

该函数的返回值一般是 NGX_OK,NGX_ERROR 和 NGX_AGAIN,分别表示处理成功,失败和未完成。

主要功能介绍

响应的主体内容就存于单链表 in,链表一般不会太长,有时 in 参数可能为 NULL。in中存有buf结构体中,对于静态文件,这个buf大小默认是 32K;对于反向代理的应用,这个buf可能是4k或者8k。为了保持内存的低消耗,Nginx一般不会分配过大的内存,处理的原则是收到一定的数据,就发送出去。一个简单的例子,可以看看Nginx的chunked_filter模块,在没有 content-length 的情况下,chunk 模块可以流式(stream)的加上长度,方便浏览器接收和显示内容。

在响应体过滤模块中,尤其要注意的是 buf 的标志位,完整描述可以在“相关结构体”这个节中看到。如果 buf 中包含 last 标志,说明是最后一块 buf,可以直接输出并结束请求了。如果有 flush 标志,说明这块 buf 需要马上输出,不能缓存。如果整块 buffer 经过处理完以后,没有数据了,你可以把 buffer 的 sync 标志置上,表示只是同步的用处。

当所有的过滤模块都处理完毕时,在最后的 write_fitler 模块中,Nginx 会将 in 输出链拷贝到 r->out 输出链的末尾,然后调用 sendfile 或者 writev 接口输出。由于 Nginx 是非阻塞的 socket 接口,写操作并不一定会成功,可能会有部分数据还残存在 r->out。在下次的调用中,Nginx 会继续尝试发送,直至成功。

发出子请求

Nginx 过滤模块一大特色就是可以发出子请求,也就是在过滤响应内容的时候,你可以发送新的请求,Nginx 会根据你调用的先后顺序,将多个回复的内容拼接成正常的响应主体。一个简单的例子可以参考 addition 模块。

Nginx 是如何保证父请求和子请求的顺序呢?当 Nginx 发出子请求时,就会调用 ngx_http_subrequest 函数,将子请求插入父请求的 r->postponed 链表中。子请求会在主请求执行完毕时获得依次调用。子请求同样会有一个请求所有的生存期和处理过程,也会进入过滤模块流程。

关键点是在 postpone_filter 模块中,它会拼接主请求和子请求的响应内容。r->postponed 按次序保存有父请求和子请求,它是一个链表,如果前面一个请求未完成,那后一个请求内容就不会输出。当前一个请求完成时并输出时,后一个请求才可输出,当所有的子请求都完成时,所有的响应内容也就输出完毕了。

一些优化措施

Nginx 过滤模块涉及到的结构体,主要就是 chain 和 buf,非常简单。在日常的过滤模块中,这两类结构使用非常频繁,Nginx采用类似 freelist 重复利用的原则,将使用完毕的 chain 或者 buf 结构体,放置到一个固定的空闲链表里,以待下次使用。

比如,在通用内存池结构体中,pool->chain 变量里面就保存着释放的 chain。而一般的 buf 结构体,没有模块间公用的空闲链表池,都是保存在各模块的缓存空闲链表池里面。对于 buf 结构体,还有一种 busy 链表,表示该链表中的 buf 都处于输出状态,如果 buf 输出完毕,这些 buf 就可以释放并重复利用了。

功能函数名chain 分配ngx_alloc_chain_linkchain 释放ngx_free_chainbuf 分配ngx_chain_get_free_bufbuf 释放ngx_chain_update_chains

过滤内容的缓存

由于 Nginx 设计流式的输出结构,当我们需要对响应内容作全文过滤的时候,必须缓存部分的 buf 内容。该类过滤模块往往比较复杂,比如 sub,ssi,gzip 等模块。这类模块的设计非常灵活,我简单讲一下设计原则:

  1. 输入链 in 需要拷贝操作,经过缓存的过滤模块,输入输出链往往已经完全不一样了,所以需要拷贝,通过 ngx_chain_add_copy 函数完成。
  2. 一般有自己的 free 和 busy 缓存链表池,可以提高 buf 分配效率。
  3. 如果需要分配大块内容,一般分配固定大小的内存卡,并设置 recycled 标志,表示可以重复利用。
  4. 原有的输入 buf 被替换缓存时,必须将其 buf->pos 设为 buf->last,表明原有的 buf 已经被输出完毕。或者在新建立的 buf,将 buf->shadow 指向旧的 buf,以便输出完毕时及时释放旧的 buf。


Tags:Nginx   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
项目中,遇到了一个问题,就是PDF等文档不能够在线预览,预览时会报错。错误描述浏览器的console中,显示如下错误:nginx代理服务报Mixed Content: The page at ******** was loaded...【详细内容】
2021-12-17  Tags: Nginx  点击:(7)  评论:(0)  加入收藏
安全服务器是只允许所需数量的服务器。理想情况下,我们将通过单独启用其他功能来基于最小系统构建服务器。进行最少的配置也有助于调试。如果该错误在最小系统中不可用,则分别...【详细内容】
2021-09-26  Tags: Nginx  点击:(60)  评论:(0)  加入收藏
在今年的NGINX Sprint 2.0虚拟大会上,NGINX(来自流行的开源web服务器/负载均衡器和反向代理背后的公司F5),发布了NGINX现代应用参考架构(MARA)。该公司在一篇博客文章中说,这将帮...【详细内容】
2021-09-26  Tags: Nginx  点击:(61)  评论:(0)  加入收藏
Nginx来限制访问控制的方法有多种,nginx主要有2个模块控制,但是那些不支持自定义,非常死,在大多数场景下并不实用。今天分享一个:利用openresty+lua+redis 实现封杀频繁恶意访问I...【详细内容】
2021-08-12  Tags: Nginx  点击:(119)  评论:(0)  加入收藏
为什么要优化 Ngin HTTPS 延迟Nginx 常作为最常见的服务器,常被用作负载均衡 (Load Balancer)、反向代理 (Reverse Proxy),以及网关 (Gateway) 等等。一个配置得当的 Nginx 服...【详细内容】
2021-08-11  Tags: Nginx  点击:(53)  评论:(0)  加入收藏
nginx 内存池 ngx_pool_tnginx 是自己实现了内存池的,所以在nginx ngx_pool_t 这个结构也随处可见,这里主要分析一下内存池的分配逻辑。内存池实现了包括小块内存、大块内存和...【详细内容】
2021-08-03  Tags: Nginx  点击:(71)  评论:(0)  加入收藏
Nginx 可视化管理,例如: 配置管理 性能监控 日志监控 其他配置1方案目前已实现前两条: 配置管理,和性能监控,日志分析监控这块还需要另找方案实现,目前方案直接套用大神开发的 ng...【详细内容】
2021-07-22  Tags: Nginx  点击:(121)  评论:(0)  加入收藏
nginx配置文件详解#启动子进程程序默认用户#user nobody;#一个主进程和多个工作进程。工作进程是单进程的,且不需要特殊授权即可运行;这里定义的是工作进程数量worker_proce...【详细内容】
2021-07-16  Tags: Nginx  点击:(87)  评论:(0)  加入收藏
作者:vbirdbestblog.csdn.net/vbirdbest/article/details/80913319一、HTTP服务器Nginx本身也是一个静态资源的服务器,当只有静态资源的时候,就可以使用Nginx来做服务器,如果一...【详细内容】
2021-07-06  Tags: Nginx  点击:(94)  评论:(0)  加入收藏
今天总结一下负载均衡中LVS与Nginx的区别,好几篇博文一开始就说LVS是单向的,Nginx是双向的,我个人认为这是不准确的,LVS三种模式中,虽然DR模式以及TUN模式只有请求的报文经过Director,但是NAT模式,Real Server回复的...【详细内容】
2021-06-08  Tags: Nginx  点击:(114)  评论:(0)  加入收藏
▌简易百科推荐
阿里云镜像源地址及安装网站地址https://developer.aliyun.com/mirror/centos?spm=a2c6h.13651102.0.0.3e221b111kK44P更新源之前把之前的国外的镜像先备份一下 切换到yumcd...【详细内容】
2021-12-27  干程序那些事    Tags:CentOS7镜像   点击:(1)  评论:(0)  加入收藏
前言在实现TCP长连接功能中,客户端断线重连是一个很常见的问题,当我们使用netty实现断线重连时,是否考虑过如下几个问题: 如何监听到客户端和服务端连接断开 ? 如何实现断线后重...【详细内容】
2021-12-24  程序猿阿嘴  CSDN  Tags:Netty   点击:(12)  评论:(0)  加入收藏
一. 配置yum源在目录 /etc/yum.repos.d/ 下新建文件 google-chrome.repovim /etc/yum.repos.d/google-chrome.repo按i进入编辑模式写入如下内容:[google-chrome]name=googl...【详细内容】
2021-12-23  有云转晴    Tags:chrome   点击:(7)  评论:(0)  加入收藏
一. HTTP gzip压缩,概述 request header中声明Accept-Encoding : gzip,告知服务器客户端接受gzip的数据 response body,同时加入以下header:Content-Encoding: gzip:表明bo...【详细内容】
2021-12-22  java乐园    Tags:gzip压缩   点击:(9)  评论:(0)  加入收藏
yum -y install gcc automake autoconf libtool makeadduser testpasswd testmkdir /tmp/exploitln -s /usr/bin/ping /tmp/exploit/targetexec 3< /tmp/exploit/targetls -...【详细内容】
2021-12-22  SofM    Tags:Centos7   点击:(7)  评论:(0)  加入收藏
Windows操作系统和Linux操作系统有何区别?Windows操作系统:需支付版权费用,(华为云已购买正版版权,在华为云购买云服务器的用户安装系统时无需额外付费),界面化的操作系统对用户使...【详细内容】
2021-12-21  卷毛琴姨    Tags:云服务器   点击:(6)  评论:(0)  加入收藏
参考资料:Hive3.1.2安装指南_厦大数据库实验室博客Hive学习(一) 安装 环境:CentOS 7 + Hadoop3.2 + Hive3.1 - 一个人、一座城 - 博客园1.安装hive1.1下载地址hive镜像路径 ht...【详细内容】
2021-12-20  zebra-08    Tags:Hive   点击:(9)  评论:(0)  加入收藏
以下是服务器安全加固的步骤,本文以腾讯云的CentOS7.7版本为例来介绍,如果你使用的是秘钥登录服务器1-5步骤可以跳过。1、设置复杂密码服务器设置大写、小写、特殊字符、数字...【详细内容】
2021-12-20  网安人    Tags:服务器   点击:(7)  评论:(0)  加入收藏
项目中,遇到了一个问题,就是PDF等文档不能够在线预览,预览时会报错。错误描述浏览器的console中,显示如下错误:nginx代理服务报Mixed Content: The page at ******** was loaded...【详细内容】
2021-12-17  mdong    Tags:Nginx   点击:(7)  评论:(0)  加入收藏
转自: https://kermsite.com/p/wt-ssh/由于格式问题,部分链接、表格可能会失效,若失效请访问原文密码登录 以及 通过密钥实现免密码登录Dec 15, 2021阅读时长: 6 分钟简介Windo...【详细内容】
2021-12-17  LaLiLi    Tags:SSH连接   点击:(16)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条