Tag: webserver

Nginx模块中调用ngx_localtime()可能死锁

March 19th, 2010

如果设定了timer_resolution并在自己的模块中调用了ngx_localtime()nginx极有可能失去响应。

原因看来是localtime_r(3)信号不安全。nginx内部会用ngx_time这个变量中存下当前的时间,默认是在每次event循环中更新这个变量,减少gettimeofday(2)的调用次数。设置timer_resolution参数会导致nginx使用SIGALRM信号来定时更新,作者认为这样会有更好的精度。触发信号处理函数ngx_timer_signal_handler()后,里面调用ngx_localtime(),最后落实到glibclocaltime_r(3)。由于localtime_r(3)信号不安全,这样自己的模块代码中也进行了ngx_localtime()调用的话,两者很容易冲突而死锁(不知道我说清楚了吗)。

这个问题看起来也没什么好修正的,不要在自己的模块里面用ngx_localtime()就好了。如果不需要设定timer_resolution,可以假装一切都很正常。我现在使用ngx_timeofday()/ngx_gmtime()来格式化时间,目前情绪稳定。

Update: nginx 0.7.66 已经修正了此问题。

参考:

ps: 为了这篇post,山寨了个在Windows Live Writer里面给选定文字加<code>标签的插件,有需要的同学吗……

Tags: , , , , ,
Posted in t | 1 Comment »

Lighttpd覆盖设置http头

December 6th, 2009

lighty 1.4 的 setenv 模块是可以操作 http 头的, 但它提供的三个指令实际只是把给定的值附加进去, 如果处理的请求本来有同名的头, 会变成这样:
Host: foo.com, bar.com

X_FORWARD_FOR 这样的头可以如此处理, 但 Host 之类就不是希望的结果了.比如作为代理时, 伺服的主机名和后端伺服的不同, 需要覆盖掉 Host 头.

lighty 1.5 和 nginx 都提供了对应的指令, 1.4 下面得自助. 这里我添加了一个 set-request-header 指令, 顾名思义(set vs add), 会用给定值覆盖设置请求头的值. 响应头的因为我用不到所以没实现, 需要的同学自己折腾吧.

patch 放在 lighty 的论坛上, 但几个月了没人理, 是没人需要鹰语太烂还是要开 issue 才行?

Tags: , , , , , , , ,
Posted in t | 2 Comments »

Nginx模块开发小记

September 4th, 2009

前阵子在折腾Nginx的模块, 很有趣.

为了方便使用调试器, 可以单进程非daemon方式启动, 使用参数:

daemon off;
master_process  off;

因为Nginx是事件驱动, 在读request body时, 第一个数据包一般发送不全, 需要异步读取余下的.

当在主handler部分调用ngx_http_read_client_request_body时, 需要注册一个回调的handler, 然后主handler直接返回NGX_DONE, 告诉Nginx留下这个请求的事件注册, 继续接收数据包.

经过若干次循环最终读完request body后, Nginx会去回调被注册的handler, 在此函数中产生响应, 最后调用ngx_http_finalize_request结束整个请求. 大概流程是:

ngx_http_foo_handler(){
    ngx_http_read_client_request_body(r, ngx_http_foo_post_handler);
    return NGX_DONE; // 主handler结束
}
ngx_http_foo_post_handler(){
    // 请求全部读完后从这里入口, 可以产生响应
    ngx_http_finalize_request(r, NGX_HTTP_OK);
}

一般的模块都是同步方式的, 我开始就没搞明白这异步读到底怎么搞, 走了不少弯路. 代码上可以简单参考dav模块, 复杂点还有upload模块.

Nginx可能会把request body放到两个buffer里面, 太大的话也可能存入文件中. 如果要在模块中读取request body进行处理, 自然不希望搞太麻烦,可以:

r->request_body_in_single_buf = 1;

使body存在一个buffer里面, 配置里面要留够需要的大小.

如果没有特殊的要求, 这类模块也可以拿 embedded perl 来写. 响应产生, sendfile都支持. Perl的开发效率自然很高, 维护也方便. 作者说此功能还是"experimental",  但实测了下没出啥问题.

我本着先写原型的目的试验了下, 结果发现性能还不错, 在双路5130机器上, perl版本的可以达到15k req/s (使用ab测试), 非常够用了.

Tags: , , , , ,
Posted in t | 4 Comments »

Lighttpd中mod_compress关于etag的一个bug

March 9th, 2008

这几日一直在摆弄lighttpd,好不容易弄的差不多了,却出现了个诡异的事情:

在1.4.18版本中,使用mod_compress给一些静态文件如js、css启用了gzip压缩之后,无论 static-file.etags 如何设置,etag头部总是会被输出。

static-file.etags 是一个1.4.15新加命令,用于控制是否启用etag。以前在Apache2上我也发现无法通过 FileETag None 关闭etag的情况。以为是协议设计使然,在rfc2616上兜了一圈,无果,八成是个bug了。在lighttpd的trac上开了一个ticket:http://trac.lighttpd.net/trac/ticket/1585

查看了mod_compress的代码,发现里面确实没去 static-file.etags 的设置,直接输出etag。看来mod_compress的作者没有注意到这个新加的命令。

花一个下午加了些hack,在Ubuntu/6.06+lighttpd/1.4.18上测试通过,能够处理 static-file.etags 选项。

patch文件可以在 http://trac.lighttpd.net/trac/attachment/ticket/1585/mod_compress.c.diff?format=raw 得到。

最后说一句:开源很好很强大。

Tags: , , , , ,
Posted in t | 4 Comments »