Nginx学习笔记(三)
过滤模块简介
执行时间和内容
过滤(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; }
从配置我们可以看出负载均衡模块的使用场景:
- 核心指令
ip_hash
只能在 upstream {}中使用。这条指令用于通知 Nginx 使用 ip hash 负载均衡算法。如果没加这条指令,Nginx 会使用默认的 round robin 负载均衡模块。 - upstream {}中的指令可能出现在
server
指令前,可能出现在server
指令后,也可能出现在两条server
指令之间。
指令
ip_hash 的指令定义如下:
钩子
负载均衡模块的钩子代码都是有规律的,这里通过 ip_hash 模块来分析这个规律。
这段代码中有两点值得注意。一个是 uscf->flags 的设置,另一个是设置 init_upstream 回调。
设置 uscf->flags
- NGX_HTTP_UPSTREAM_CREATE:创建标志,如果含有创建标志的话,Nginx 会检查重复创建,以及必要参数是否填写;
- NGX_HTTP_UPSTREAM_MAX_FAILS:可以在 server 中使用 max_fails 属性;
- NGX_HTTP_UPSTREAM_FAIL_TIMEOUT:可以在 server 中使用 fail_timeout 属性;
- NGX_HTTP_UPSTREAM_DOWN:可以在 server 中使用 down 属性;
- NGX_HTTP_UPSTREAM_WEIGHT:可以在 server 中使用 weight 属性;
- 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学习笔记(三)相关推荐
- nginx学习笔记-01nginx入门,环境搭建,常见命令
nginx学习笔记-01nginx入门,环境搭建,常见命令 文章目录 nginx学习笔记-01nginx入门,环境搭建,常见命令 1.nginx的基本概念 2.nginx的安装,常用命令和配置文件 3 ...
- 【005】Nginx学习笔记-Nginx真实IP
[005]Nginx学习笔记-Nginx真实IP 真实IP 客户端真实IP 深入理解真实IP 实验一 实验二: 多个代理服务器的情况 实验三:利用realip模块获取客户端真实IP 实验四:伪装请求头 ...
- 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 个重要概念 ...
- 全是精髓!也许是最完美的“Nginx学习笔记”了,阿里云高工“365”天手写!
前言 "Nginx",一个高性能的HTTP和反向代理web服务器,Nginx因为内存少.并发能力强的特性,深受虚拟机主机提供商的欢迎,可以支持高达50000个并发连接数的响应.Ng ...
- Nginx 学习笔记
Nginx 学习笔记 文章目录 Nginx 学习笔记 1.Nginx 的简介 1.1正向代理 1.2反向代理 1.3负载均衡 1.4动静分离 1.5Nginx的安装 1.6Nginx的常用命令 1.7 ...
- J2EE学习笔记三:EJB基础概念和知识 收藏
J2EE学习笔记三:EJB基础概念和知识 收藏 EJB正是J2EE的旗舰技术,因此俺直接跳到这一章来了,前面的几章都是讲Servlet和JSP以及JDBC的,俺都懂一些.那么EJB和通常我们所说的Ja ...
- tensorflow学习笔记(三十二):conv2d_transpose (解卷积)
tensorflow学习笔记(三十二):conv2d_transpose ("解卷积") deconv解卷积,实际是叫做conv_transpose, conv_transpose ...
- Ethernet/IP 学习笔记三
Ethernet/IP 学习笔记三 原文为硕士论文: 工业以太网Ethernet/IP扫描器的研发 知网网址: http://kns.cnki.net/KCMS/detail/detail.aspx? ...
- nginx 学习笔记(2) nginx新手入门
这篇手册简单介绍了nginx,并提供了一些可以操作的简单的工作.前提是nginx已经被安装到你的服务器上.如果没有安装,请阅读上篇:nginx 学习笔记(1) nginx安装.这篇手册主要内容:1. ...
- iView学习笔记(三):表格搜索,过滤及隐藏列操作
iView学习笔记(三):表格搜索,过滤及隐藏某列操作 1.后端准备工作 环境说明 python版本:3.6.6 Django版本:1.11.8 数据库:MariaDB 5.5.60 新建Django ...
最新文章
- [AHOI 2016初中组]迷宫
- AI:2020年6月16日晚20点陆奇博士演讲《陆奇直播万字实录:正视挑战,把握创业创新机会》
- linux——mysql5.5 安装遇到问题总结解决方式
- linux samba服务器
- thrift linux java,Apache Thrift环境配置
- 使用struts2的 下载
- [转]将微信和支付宝支付的个二维码合二为一
- 外呼机器人起名_电销外呼机器人如此受欢迎,今天终于知道原因了
- C#如何关闭指定进程
- [VNC] VNC Viewer 远程运行 ffplay 出现错误 GLXBadRenderRequest
- C语言经典题目(51-60)
- VS 2015 搭建Google Test
- 深入理解JavaScript系列(13):This? Yes,this!
- 苹果id是什么格式的_长春苹果x主板维修推荐,苹果ipad12.9死机,商业资讯
- 求一亿以内的回文质数(素数)
- blender使用stereoscopy渲染输出VR图片和视频
- CRISPR-Cas9实验常见问题及解决方案
- 尚硅谷nginx笔记
- nodejs批量ping
- Unity CardboardSDK解析
热门文章
- 2018-2019-1 20165202 《信息安全系统设计基础》第四周学习总结
- 安装asterisk 时遇到的报错情况,及解决办法。
- apache工作模式
- 【转】NSMutableArray的正确使用
- 使用.NET中的XML注释(一) -- XML注释标签讲解
- Android是否会因低价打败iPhone
- python全栈工程师百科_Python全栈工程师(列表、拷贝)
- 上海交通大学医学院附属瑞金医院首次公布预警期刊
- android air创建文件夹,安卓版Airdrop将上线:无需安装APP,轻松实现文件隔空投送...
- ST_Curve --- 一个专业的曲线绘制控件