upstream和subrequest

<深入理解Nginx模块开发与架构解析>--陶辉

upstream

1,upstream与subrequest的作用范围:如果希望把第三方服务的内容几乎原封不动的返回给用户,一般使用upstream方式,如果访问第三方服务只是为了获取某些信息,在根据这些信息构造响应则应采取subrequest方式。

2,upstream机制的使用关键在于设置ngx_http_request_t的upstream成员,包括 a,upstream的配置信息:

一般将ngx_http_upstream_conf_t封装在自己模块自定义的配置结构体中,可以采用预定义的配置解析函数进行获取配置参数信息。

b,三个必须设置的回调函数:

ngx_int_t
(*create_request) (ngx_http_request_t *r);

ngx_int_t
(*process_header) (ngx_http_request_t *r);

ngx_int_t
(*finalize_request) (ngx_http_request_t *r);

必须设置的原因在于nginx会调用对应的函数指针,如果不设置的话初始化为 NULL,会出现调用空指针的错误。

c,上游服务器地址:

ngx_http_upstream_resolved_t
*resolved;

d,启动upstream

调用ngx_http_upstream_init方法,需要对r->main->count引用计数加1,这是在告诉HTTP框架将当前请求的引用计数加1,即告诉ngx_http_mytest_handler方法暂时不要销毁请求,因为HTTP框架只有在引用计数为0时才会真正的销毁请求。返回NGX_DONE告诉HTTP框架暂停执行请求的下一阶段。

上述步骤结合起来就构成了通过upstream访问第三方服务器的模块。

3,在process_header和handler函数中都需要设置上下文,HTTP框架提供了ngx_http_status_t结构体作为上下文,使用时将其封装在自己定义的上下文结构体中,作为唯一的结构体成员。

4,回调方法的执行:

create_request只会被调用1次,而reinit_request则可能被调用多次,被调用的原因就是在第一次想上游服务器建立连接时失败。

finalize_request可以不做任何事情,但必须实现,否则会出现空指针调用的严重错误。

process_header用于解析上游服务器返回的基于TCP的响应头部,因此,它可能被调用多次,调用次数与process_header的返回值有关,如果返回NGX_AGAIN,说明没有接收到完整的响应头部,当再次接收到上游的TCP流时,还会将其当作TCP头部,调用process_header进行处理。

5,模块实现

配置项参数,每一个HTTP请求会有一个独立的ngx_http_upstream_conf_t结构体,本模块中所有请求共享一个ngx_http_upstream_conf_t结构体。

请求上下文,解析HTTP响应行时可以使用HTTP框架提供的ngx_http_status_t结构。需要请求上下文的原因在于,upstream模块每次接收到一段TCP流时都会回调mytest模块实现的process_header方法,需要有一个上下文保存解析状态。三个必须设置的回调函数中只有process_header是可能被多次回调的。

create_request,构造发往上游服务器的请求采用ngx_buf_t动态分配内存形式,一是向上游发送的请求可能会经过epoll多次调用,这时必须保证该请求始终有效,二是请求结束时内存会被自动释放,降低了内存泄漏。将ngx_alloc_chain_link返回的指针赋值给r->upstream->request_bufs,request_bufs成员是决定向上游发送什么样的请求,它是一个ngx_chain_t结构体。最后就是设置r->upstream的状态位,并将

r->header_hash赋值为1,不能为0。

process_header,负责解析上游服务器发来的基于TCP的包头。本模块中就是解析HTTP响应行和HTTP头部。模块使用

mytest_process_status_line和

mytest_upstream_process_header

解析HTTP响应行和HTTP响应头部。两个方法是通用的,适用于解析所有的HTTP响应包。之所以使用两个方法解析包头,主要是无论是响应行还是响应头部都是不定长的,需要使用状态机来解析。HTTP框架分别提供了

ngx_http_parse_status_line和

ngx_http_parse_header_line

来解析HTTP响应行和HTTP响应头部。当解析到完整的HTTP响应行时,会将解析出的信息设置到r->upstream->headers_in结构体中。当upstream解析完所有的包头时,会把headers_in中的成员设置到将要向下游发送的r->headers_out结构体中。当解析完HTTP响应头部时,简单的将上游服务器发送的HTTP头部添加到请求

r->upstream->headers_in.headers链表中即可。如果有需要特殊处理的HTTP头部,需要在mytest_upstream_process_header中进行。

finalize_request,本模块中没有需要释放的资源,简单做一个日志记录用于调试,NGX_LOG_DEBUG。

ngx_http_mytest_handler,在模块主方法中建立HTTP上下文结构体,仅调用一次ngx_http_upstream_create方法初始化r->upstream成员,获取配置结构体并赋值

r->upstream->conf成员,设置上游服务器地址,设置3个回调方法,将r->main->count加1,调用ngx_http_upstream_init启动upstream,完毕。

subrequest

1,与upstream的关系

a,只要不是完全将上游服务器的响应包体转发到下游客户端,基本上都会使用subquest创建出子请求,并由子请求使用upstream机制访问上游服务器,然后由父请求根据上游响应重新构造返回给下游客户端的响应。

b,在HTTP框架的设计上,二者是密切相关的。

2,使用步骤

a,在nginx.conf文件中配置好子请求的处理方式

b,启动subquest子请求

c,实现子请求处理完毕时的回调方法

d,实现父请求被激活时的回调方法

子请求与普通请求的不同之处在于,子请求是由父请求生成的,不是接收客户端发来的网络包再由HTTP框架解析出的。配置处理子请求的模块与普通请求完全一样,可以使用任意HTTP官方模块,第三方模块来处理。

3,两个回调方法

子请求处理完毕时回调方法对应指针:

typedef
ngx_int_t (*ngx_http_post_subrequest_pt) (ngx_http_request_t *r,

void
*data, ngx_int_t rc);

在该回调方法中必须设置另一个回调方法,即父请求被激活的处理方法,也就是父请求ngx_http_request_t的write_event_handler成员。父请求ngx_http_request_t可以通过子请求ngx_http_request_t
*r的r->parent成员获得。

父请求被重新激活后回调方法对应指针:

typedef
void (*ngx_http_event_handler_pt) (ngx_http_request_t*
r);

4,启动subrequest

调用

ngx_int_t

ngx_http_subrequest(ngx_http_request_t
*r, ngx_str_t *rui, ngx_str_t *args,

ngx_http_request_t
**psr, ngx_http_post_subrequest_t *ps,

ngx_uint_t
flags);

方法建立子请求。

转发上游响应

在不转发响应时,upstream会将上游响应全部保存到r->upstream->buffer中,buffer是一个ngx_buf_t结构体。

子请求结束后如何激活父请求

当事件模块检测到网络关闭事件而这个请求的处理方法属于upstream模块时,调用ngx_http_upstream_finalize_request方法就诶书upstream机制下的请求。它会检查当前请求是否是子请求,是的话就调用我们写的回调函数mytest_subrequest_post_handler,子请求的回调执行完毕之后,finalize_request继续执行直到完毕,然后HTTP框架发现当前请求还有父请求需要执行,则调用父请求的write_event_handler回调方法。

详见P193

时间: 2024-12-17 12:45:56

upstream和subrequest的相关文章

Nginx 中的 upstream 与 subrequest 机制

概述 Nginx 提供了两种全异步方式与第三方服务进行通信:upstream 和 subrequest.upstream 在与第三方服务器交互时(包括建立 TCP 连接.发送请求.接收响应.关闭 TCP 连接),不会阻塞 Nginx 进程处理其他请求.subrequest 只是分解复杂请求的一种设计模式,它可以把原始请求分解为多个子请求,使得诸多请求协同完成一个用户请求,并且每个请求只关注一个功能.subrequest 访问第三方服务最终也是基于 upstream 实现的. upstream 被

【高性能服务器】Nginx剖析

引言 Nginx是一个流行的高性能服务器,官方宣称在压力测试下可以支持5万个并发连接,而且占用内存极低.相比于其他昂贵的硬件负载均衡解决方案,Nginx是开源免费的,可以大大降低成本.本文将从一下几个方面来剖析其内部结构. 特点 进程模型 惊群效应 负载均衡 核心模块 模块分类 事件驱动模块机制 反向代理模块 配置文件 Nginx的特点 Nginx是俄罗斯工程师开发的高性能Web服务器,为了实现高效Nginx全部采用C语言编写,因为底层对不同的操作系统进行了封装,所以Nginx实现了平台无关性.

nginx upstream使用及源码解析

nginx upstream机制使得nginx可以成为一个反向代理服务器,nginx一方面从下游客户端接收http请求,处理请求,并根据请求发送tcp报文到上游服务器,根据上游服务器的返回报文,来向下游客户端发送请求响应报文. upstream机制也提供了负载分担的功能,可以将请求负载分担到集群服务器的某个服务器上面. 2.1upstream的流程介绍 1分析客户端请求报文,构建发往上游服务器的请求报文. 2调用ngx_http_upstream_init开始与上游服务器建立tcp连接. 3发送

Nginx 中 upstream 机制的实现

概述 upstream 机制使得 Nginx 成为一个反向代理服务器,Nginx 接收来自下游客户端的 http 请求,并处理该请求,同时根据该请求向上游服务器发送 tcp 请求报文,上游服务器会根据该请求返回相应地响应报文,Nginx 根据上游服务器的响应报文,决定是否向下游客户端转发响应报文.另外 upstream 机制提供了负载均衡的功能,可以将请求负载均衡到集群服务器的某个服务器上面. 启动 upstream 在 Nginx 中调用 ngx_http_upstream_init 方法启动

nginx之upstream集中分配方式

一.分配方式 1.轮询方式(默认) upstream realserver {     server 192.168.1.1;     server 192.168.1.2; } 每一个请求会按照时间顺序分配到后端不同的服务器上,假如有一台服务器宕机,则会自动剔除该服务器. 2.weight权重 upstream realserver {         server 192.168.1.1 weight=5;         server 192.168.1.2 weight=8; } 根据后

centos nginx upstream nextserver的写法一例

http { proxy_next_upstream error timeout http_500 http_502 http_503 http_504 http_404; proxy_connect_timeout 60s; proxy_read_timeout 120s; server { location / { proxy_next_upstream error timeout http_502 http_404; proxy_connect_timeout 5s; proxy_read

Merging an upstream repository into your fork

1. Check out the branch you wish to merge to. Usually, you will merge into master. $ git checkout master 2. Pull the desired branch from the upstream repository. This method will retain the commit history without modification. $ git pull https://gith

nginx 502错误 upstream sent too big header while reading response header from upstream

原本的设置是 proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; 在这种配置下,使用fiddler进行抓包分析,发现只要请求的header的尺寸大于4378字节的时候就报502,当header在4377及以下的时候就正常了. 将配置更改为: proxy_buffer_size 64k;   proxy_buffers   32 32k;   proxy_busy_buffers_size 128k; 之后

nginx反向代理tomcat提示13 permission denied while connecting to upstream

nginx反向代理tomcat提示13 permission denied while connecting to upstream,网上很多都是说13 permission denied while reading to upstream,这是两个完全不同的错误,我遇到的如下截图: 查看selinux日志发现错误: 后来发现是selinux的问题,于是先关掉selinux:setenforce 0:然后再访问果然好使. 于是启用selinux,再执行下面的命令,修改selinux的值: set