Chinaunix首页 | 论坛 | 博客
  • 博客访问: 179915
  • 博文数量: 23
  • 博客积分: 413
  • 博客等级: 一等列兵
  • 技术积分: 365
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-28 15:31
个人简介

杭州智链达数据有限公司技术总监,兼联合创始人

文章分类
文章存档

2018年(2)

2017年(4)

2012年(15)

2011年(2)

分类: 系统运维

2012-01-16 21:01:19

nginx是个高性能web server,很多时候我们会把它当成reverse proxy或者web server container使用,但有时我们也会开发它的第三方module,因为module才能完全使用nginx的全事件驱动、无阻塞调用机制,充分使用系统资源,达到SERVER最大处理吞吐量。


在开发nginx module时,我们最有可能遇到的一件事就是,在处理一个请求时,我们需要访问其他多个backend server网络资源,拉取到结果后分析整理成一个response,再发给用户。这个过程是无法使用nginx upstream机制的,因为upstream被设计为用来支持nginx reverse proxy功能,所以呢,upstream默认是把其他server的http response body全部返回给client。这与我们的要求不符,这个时候,我们可以考虑subrequest了,nginx http模块提供的这个功能能够帮我们搞定它。


先看看subrequest调用函数长什么样:

  1. ngx_int_t  
  2. ngx_http_subrequest(ngx_http_request_t *r,  
  3.     ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr,  
  4.     ngx_http_post_subrequest_t *ps, ngx_uint_t flags)  

挨个分析下参数吧。r是我们的module handler中,nginx调用时传给我们的请求,这时我们直接传给subrequest即可。uri和args是我们需要访问backend server的URL,而psr是subrequest函数执行完后返回给我们的新请求,即将要访问backend server的请求指针。ps指明了回调函数,就是说,如果这个请求执行完毕,接收到了backend server的响应后,就会回调这个函数。flags会指定这个子请求的一些特征。

看看ngx_http_post_subrequest的结构:

  1. typedef struct {  
  2.     ngx_http_post_subrequest_pt       handler;  
  3.     void                             *data;  
  4. } ngx_http_post_subrequest_t;  

这里的handler你可以指向一个函数,这个函数会在这个子请求结束以后被nginx调用,这时传给函数的request是子请求,不是原始的父请求哈。


而flag我们一般只会感兴趣下面这个NGX_HTTP_SUBREQUEST_IN_MEMORY,flag设为这个宏时,表示发起的子请求,访问的网络资源返回的响应将全部放在内存中,我们可以从upstream->buffer里取到响应内容。所以这里如果用了这个flag,一定要确保返回内容不可以很大,例如不能去下载一个大文件。


所以,当我们写nginx的module时,需要去拉取某个网络资源,就可以这么写:

  1.   ngx_http_post_subrequest_t          *psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));  
  2.   
  3.   if (psr == NULL) {  
  4.       return NGX_HTTP_INTERNAL_SERVER_ERROR;  
  5.   }  
  6.   
  7.   psr->handler = ngx_http_my_post_subrequest;  
  8.   psr->data = ctx;  
  9. ngx_flag_t flag = NGX_HTTP_SUBREQUEST_IN_MEMORY   
  10. ngx_str_t sub_location = ngx_string("/testlocation");  
  11. ngx_str_t sub_args = ngx_string("para=1");;  
  12.   rc = ngx_http_subrequest(r, &sub_location, &url_args, &sr, psr, sr_flag);  

这样,在这个subrequest执行完后,将会调用ngx_http_my_post_subrequest方法,再次注意,此时传给你的ngx_http_request_t上下文是子请求的,不是原始的父请求,所以,如果你需要在父请求的上下文中处理这个请求,可以在ngx_http_my_post_subrequest中找到父请求的handler,设置为一个处理函数即可。比如:

  1. ngx_http_request_t          *pr = r->parent;  
  2. pr->write_event_handler = ngx_http_parent_handler;  

这样,这个ngx_http_my_post_subrequest执行完毕后,nginx开始换醒父请求,这时ngx_http_parent_handler将会被调用。


最后我们要注意,一个请求中,我们只能调用一次subrequest,不能一次生成多个subrequest。我们可以在儿子请求中再创建孙子请求,一直下去都行,但是不能一次创建多个子请求。为什么呢?因为nginx本身的设计就是,每处理完一个事件后,将会检查有没有它对应的一个post事件(一对一),如果有则处理。上面的subrequest就是用这个流程的。如果一个请求中我们想同时生成多个子请求,就不能用subrequest了,我们必须自己创建nginx事件来处理了。

阅读(2689) | 评论(1) | 转发(1) |
给主人留下些什么吧!~~

我要去鸟巢2012-01-21 00:52:56

一个请求中,我们只能调用一次subrequest,不能一次生成多个subreques学习了!