过滤模块简介

执行时间和内容

过滤(filter)模块是过滤响应头和内容的模块,可以对回复的头和内容进行处理。它的处理时间在获取回复内容之后,向用户发送响应之前。它的处理过程分为两个阶段,过滤 HTTP 回复的头部和主体,在这两个阶段可以分别对头部和主体进行修改。

执行顺序

过滤模块的调用是有顺序的且在编译时决定。控制编译的脚本位于 auto/modules 中,当你编译完 Nginx 以后,可以在 objs 目录下面看到一个 ngx_modules.c 的文件。打开这个文件,有类似的代码:

ngx_module_t *ngx_modules[] = { ... &ngx_http_write_filter_module, &ngx_http_header_filter_module, &ngx_http_chunked_filter_module, &ngx_http_range_header_filter_module, &ngx_http_gzip_filter_module, &ngx_http_postpone_filter_module, &ngx_http_ssi_filter_module, &ngx_http_charset_filter_module, &ngx_http_userid_filter_module, &ngx_http_headers_filter_module, &ngx_http_copy_filter_module, &ngx_http_range_body_filter_module, &ngx_http_not_modified_filter_module, NULL };

从 write_filter 到 not_modified_filter,模块的执行顺序是反向的。即最早执行的是 not_modified_filter,然后各个模块依次执行。一般情况下,第三方过滤模块的 config 文件会将模块名追加到变量 HTTP_AUX_FILTER_MODULES 中,此时该模块只能加入到 copy_filter 和 headers_filter 模块之间执行。

模块编译

Nginx 可以加入第三方的过滤模块。在过滤模块的目录里,首先要加入 config 文件,文件的内容如下:

ngx_addon_name=ngx_http_example_filter_module HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_example_filter_module" NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_example_filter_module.c"

把名为 ngx_http_example_filter_module 的过滤模块加入,ngx_http_example_filter_module.c 是该模块的源代码。

过滤模块的分析

相关结构体

ngx_chain_t 结构是一个单向链表:

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

在过滤模块中,所有输出的内容都是通过一条单向链表所组成。单向链表的设计好处是简单,非阻塞,但是跨链表的内容操作非常麻烦,如果需要跨链表,很多时候只能缓存链表的内容。

单链表负载的就是 ngx_buf_t,该结构体使用非常广泛,该结构体的代码如下:

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

响应头过滤函数

该函数主要用处是处理 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,分别表示处理成功,失败和未完成。

响应体过滤函数

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

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

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

子请求

Nginx 过滤模块可以发出子请求,即在过滤响应内容的时候,可以发送新的请求,Nginx 会根据调用的先后顺序,将多个回复的内容拼接成正常的响应主体。

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

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

upstream 模块

upstream模块简介

模块简介

upstream 模块使 Nginx 跨越单机的限制,完成网络数据的接收、处理和转发。数据转发功能,为 Nginx 提供了跨越单机的横向处理能力,使 Nginx 摆脱只能为终端节点提供单一功能的限制,而使它具备了网路应用级别的拆分、封装和整合的战略功能。

模块接口

upstream 模块需要开发若干回调函数,完成构造请求和解析响应等具体的工作。

这些回调函数如下表所示:

SN 描述
create_request 生成发送到后端服务器的请求缓冲(缓冲链),在初始化 upstream 时使用。
reinit_request 在某台后端服务器出错的情况,Nginx会尝试另一台后端服务器。Nginx 选定新的服务器以后,会先调用此函数,以重新初始化 upstream 模块的工作状态,然后再次进行 upstream 连接。
process_header 处理后端服务器返回的信息头部。所谓头部是与 upstreamserver 通信的协议规定的,比如 HTTP 协议的 header 部分,或者 memcached 协议的响应状态部分。
abort_request 在客户端放弃请求时被调用。不需要在函数中实现关闭后端服务器连接的功能,系统会自动完成关闭连接的步骤,所以一般此函数不会进行任何具体工作。
finalize_request 正常完成与后端服务器的请求后调用该函数,与 abort_request 相同,一般也不会进行任何具体工作。
input_filter 处理后端服务器返回的响应正文。Nginx 默认的 input_filter 会将收到的内容封装成为缓冲区链 ngx_chain。该链由 upstream 的 out_bufs 指针域定位,所以开发人员可以在模块以外通过该指针 得到后端服务器返回的正文数据。memcached 模块实现了自己的 input_filter,在后面会具体分析这个模块。
input_filter_init 初始化 input filter 的上下文。Nginx 默认的 input_filter_init 直接返回。

memcached 模块

memcache 是一款高性能的分布式 cache 系统,memcache 定义了一套私有通信协议,使得不能通过 HTTP 请求来访问 memcache。

Nginx 提供了 ngx_http_memcached 模块,提供从 memcache 读取数据的功能,而不提供向 memcache 写数据的功能。

ngx_http_memcached_handler固定的操作流程如下:

1.创建 upstream 数据结构。

if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; }

2.设置模块的 tag 和 schema。schema 现在只会用于日志,tag 会用于 buf_chain 管理。

u = r->upstream; ngx_str_set(&u->schema, "memcached://"); u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module;

3.设置 upstream 的后端服务器列表数据结构。

mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module); u->conf = &mlcf->upstream;

4.设置 upstream 回调函数。在这里列出的代码稍稍调整了代码顺序。

5.创建并设置 upstream 环境数据结构。

6.完成 upstream 初始化并进行收尾工作。

r->main->count++; ngx_http_upstream_init(r); return NGX_DONE;

任何 upstream 模块,简单如 memcached,复杂如 proxy、fastcgi 都是如此。不同的 upstream 模块在这 6 步中的最大差别会出现在第 2、3、4、5 上。其中第 2、4 两步很容易理解,不同的模块设置的标志和使用的回调函数肯定不同。第 5 步也不难理解,只有第3步是最为晦涩的,不同的模块在取得后端服务器列表时,策略的差异非常大。第 6 步是一个常态。将 count 加 1,然后返回 NGX_DONE。

回调函数

  • ngx_http_memcached_create_request:按照设置的内容生成一个 key,接着生成一个“get $key”的请求,放在 r->upstream->request_bufs 里面。
  • ngx_http_memcached_reinit_request:无需初始化。
  • ngx_http_memcached_abort_request:无需额外操作。
  • ngx_http_memcached_finalize_request:无需额外操作。
  • ngx_http_memcached_process_header:模块的业务重点函数。
  • ngx_http_memcached_filter_init:修正从后端服务器收到的内容长度。因为在处理 header 时没有加上这部分长度。
  • ngx_http_memcached_filter:memcached 模块是少有的带有处理正文的回调函数的模块。因为 memcached 模块需要过滤正文末尾 CRLF “END” CRLF,所以实现了自己的 filter 回调函数。处理正文的实际意义是将从后端服务器收到的正文有效内容封装成 ngx_chain_t,并加在 u->out_bufs 末尾。Nginx 并不进行数据拷贝,而是建立 ngx_buf_t 数据结构指向这些数据内存区,然后由 ngx_chain_t 组织这些 buf。

负载均衡模块

模块简介

负载均衡模块用于从upstream指令定义的后端主机列表中选取一台主机。Nginx 先使用负载均衡模块找到一台主机,再使用 upstream 模块实现与这台主机的交互。

配置

在配置文件中,我们如果需要使用 ip hash 的负载均衡算法。我们需要写一个类似下面的配置:

upstream test { ip_hash; server 192.168.0.1; server 192.168.0.2; }

从配置我们可以看出负载均衡模块的使用场景:

  1. 核心指令ip_hash只能在 upstream {}中使用。这条指令用于通知 Nginx 使用 ip hash 负载均衡算法。如果没加这条指令,Nginx 会使用默认的 round robin 负载均衡模块。
  2. upstream {}中的指令可能出现在server指令前,可能出现在server指令后,也可能出现在两条server指令之间。

指令

ip_hash 的指令定义如下:

钩子

负载均衡模块的钩子代码都是有规律的,这里通过 ip_hash 模块来分析这个规律。

这段代码中有两点值得注意。一个是 uscf->flags 的设置,另一个是设置 init_upstream 回调。

设置 uscf->flags

  1. NGX_HTTP_UPSTREAM_CREATE:创建标志,如果含有创建标志的话,Nginx 会检查重复创建,以及必要参数是否填写;
  2. NGX_HTTP_UPSTREAM_MAX_FAILS:可以在 server 中使用 max_fails 属性;
  3. NGX_HTTP_UPSTREAM_FAIL_TIMEOUT:可以在 server 中使用 fail_timeout 属性;
  4. NGX_HTTP_UPSTREAM_DOWN:可以在 server 中使用 down 属性;
  5. NGX_HTTP_UPSTREAM_WEIGHT:可以在 server 中使用 weight 属性;
  6. NGX_HTTP_UPSTREAM_BACKUP:可以在 server 中使用 backup 属性。

在负载均衡模块的指令处理函数中可以设置并修改 upstream{} 中server指令支持的属性。

设置 init_upstream 回调

Nginx 初始化 upstream 时,会在 ngx_http_upstream_init_main_conf 函数中调用设置的回调函数初始化负载均衡模块。

初始化配置

IP hash 模块初始化配置的代码如下:

ngx_http_upstream_init_round_robin(cf, us); us->peer.init = ngx_http_upstream_init_ip_hash_peer;

IP hash 模块首先调用另一个负载均衡模块 Round Robin 的初始化函数,然后再设置自己的处理请求阶段初始化钩子。实际上几个负载均衡模块可以组成一条链表,每次都是从链首的模块开始进行处理。如果模块决定不处理,可以将处理权交给链表中的下一个模块。这里,IP hash 模块指定 Round Robin 模块作为自己的后继负载均衡模块,所以在自己的初始化配置函数中也对 Round Robin 模块进行初始化。

初始化请求

Nginx 收到一个请求后,如果发现需要访问 upstream,就会执行对应的 peer.init 函数。这是在初始化配置时设置的回调函数。这个函数最重要的作用是构造一张表,当前请求可以使用的 upstream 服务器被依次添加到这张表中。

为了讨论 peer.init 的核心,还要看 IP hash 模块的实现:

第一行是设置数据指针,这个指针就是指向前面提到的那张表;

第二行是调用 Round Robin 模块的回调函数对该模块进行请求初始化。

第三行是设置一个新的回调函数get。该函数负责从表中取出某个服务器。除了 get 回调函数,还有另一个r->upstream->peer.free的回调函数。该函数在 upstream 请求完成后调用,负责做一些善后工作。

Nginx学习笔记(三)相关推荐

  1. nginx学习笔记-01nginx入门,环境搭建,常见命令

    nginx学习笔记-01nginx入门,环境搭建,常见命令 文章目录 nginx学习笔记-01nginx入门,环境搭建,常见命令 1.nginx的基本概念 2.nginx的安装,常用命令和配置文件 3 ...

  2. 【005】Nginx学习笔记-Nginx真实IP

    [005]Nginx学习笔记-Nginx真实IP 真实IP 客户端真实IP 深入理解真实IP 实验一 实验二: 多个代理服务器的情况 实验三:利用realip模块获取客户端真实IP 实验四:伪装请求头 ...

  3. K8S 学习笔记三 核心技术 Helm nfs prometheus grafana 高可用集群部署 容器部署流程

    K8S 学习笔记三 核心技术 2.13 Helm 2.13.1 Helm 引入 2.13.2 使用 Helm 可以解决哪些问题 2.13.3 Helm 概述 2.13.4 Helm 的 3 个重要概念 ...

  4. 全是精髓!也许是最完美的“Nginx学习笔记”了,阿里云高工“365”天手写!

    前言 "Nginx",一个高性能的HTTP和反向代理web服务器,Nginx因为内存少.并发能力强的特性,深受虚拟机主机提供商的欢迎,可以支持高达50000个并发连接数的响应.Ng ...

  5. Nginx 学习笔记

    Nginx 学习笔记 文章目录 Nginx 学习笔记 1.Nginx 的简介 1.1正向代理 1.2反向代理 1.3负载均衡 1.4动静分离 1.5Nginx的安装 1.6Nginx的常用命令 1.7 ...

  6. J2EE学习笔记三:EJB基础概念和知识 收藏

    J2EE学习笔记三:EJB基础概念和知识 收藏 EJB正是J2EE的旗舰技术,因此俺直接跳到这一章来了,前面的几章都是讲Servlet和JSP以及JDBC的,俺都懂一些.那么EJB和通常我们所说的Ja ...

  7. tensorflow学习笔记(三十二):conv2d_transpose (解卷积)

    tensorflow学习笔记(三十二):conv2d_transpose ("解卷积") deconv解卷积,实际是叫做conv_transpose, conv_transpose ...

  8. Ethernet/IP 学习笔记三

    Ethernet/IP 学习笔记三 原文为硕士论文: 工业以太网Ethernet/IP扫描器的研发 知网网址: http://kns.cnki.net/KCMS/detail/detail.aspx? ...

  9. nginx 学习笔记(2) nginx新手入门

    这篇手册简单介绍了nginx,并提供了一些可以操作的简单的工作.前提是nginx已经被安装到你的服务器上.如果没有安装,请阅读上篇:nginx 学习笔记(1) nginx安装.这篇手册主要内容:1. ...

  10. iView学习笔记(三):表格搜索,过滤及隐藏列操作

    iView学习笔记(三):表格搜索,过滤及隐藏某列操作 1.后端准备工作 环境说明 python版本:3.6.6 Django版本:1.11.8 数据库:MariaDB 5.5.60 新建Django ...

最新文章

  1. [AHOI 2016初中组]迷宫
  2. AI:2020年6月16日晚20点陆奇博士演讲《陆奇直播万字实录:正视挑战,把握创业创新机会》
  3. linux——mysql5.5 安装遇到问题总结解决方式
  4. linux samba服务器
  5. thrift linux java,Apache Thrift环境配置
  6. 使用struts2的 下载
  7. [转]将微信和支付宝支付的个二维码合二为一
  8. 外呼机器人起名_电销外呼机器人如此受欢迎,今天终于知道原因了
  9. C#如何关闭指定进程
  10. [VNC] VNC Viewer 远程运行 ffplay 出现错误 GLXBadRenderRequest
  11. C语言经典题目(51-60)
  12. VS 2015 搭建Google Test
  13. 深入理解JavaScript系列(13):This? Yes,this!
  14. 苹果id是什么格式的_长春苹果x主板维修推荐,苹果ipad12.9死机,商业资讯
  15. 求一亿以内的回文质数(素数)
  16. blender使用stereoscopy渲染输出VR图片和视频
  17. CRISPR-Cas9实验常见问题及解决方案
  18. 尚硅谷nginx笔记
  19. nodejs批量ping
  20. Unity CardboardSDK解析

热门文章

  1. 2018-2019-1 20165202 《信息安全系统设计基础》第四周学习总结
  2. 安装asterisk 时遇到的报错情况,及解决办法。
  3. apache工作模式
  4. 【转】NSMutableArray的正确使用
  5. 使用.NET中的XML注释(一) -- XML注释标签讲解
  6. Android是否会因低价打败iPhone
  7. python全栈工程师百科_Python全栈工程师(列表、拷贝)
  8. 上海交通大学医学院附属瑞金医院首次公布预警期刊
  9. android air创建文件夹,安卓版Airdrop将上线:无需安装APP,轻松实现文件隔空投送...
  10. ST_Curve --- 一个专业的曲线绘制控件