Re: 关于NGINX异步事件问题

315 views
Skip to first unread message

agentzh

unread,
Aug 10, 2012, 10:33:59 PM8/10/12
to Hui Yu, openresty, 王晓哲
Hello!

2012/8/10 Hui Yu wrote:
> 问题描述:
>
> 目前我正在设计编写一通用的访问Oracle数据库的NGINX插件(handler),由于OCI没有提供异步操作机制,为提高TPS,因此想通过多线程方式解决这一问题,原理如下:
>
> Client -> Nginx -> Queue <- 多线程 -> OCI -> Oracle
>
> Client请求通过NGINX插件,放置在请求队列ReqQue中(放置的数据为:ngx_http_request_t),并且在ngx_http_request_t添加一状态属性以标识该请求的处理状态.proc_status,并置其值为waiting.
>
> 每个Work进程默认开启N个线程异步处理ReqQue队列中的请求,处理完毕后将proc_status置为done
>
> 当NGINX下一次事件来临时,发现proc_status为处理完毕,则返回Client,否则继续等待下一次事件
>
>
> “继续等待下一次事件”在handler中的代码为
> r->read_event_handler = ngx_http_request_empty_handler;
> r->write_event_handler = ngx_http_handler;
> ngx_http_post_request(r, NULL);
> return NGX_AGAIN;
>
> 进行压力测试时发现此种方式,响应时间10多秒,且随着时间的增长,响应时间也会增加,单个请求响应时间最短为0.2秒,最长3秒
>
>
> 请问“继续等待下一次事件”如何实现?,请给予指点,万分感谢!

大约二三年前,chaoslawful 老师曾尝试编写过 ngx_oracle 模块,并且貌似已经得到了一个可以运行的原型?我听
chaoslawful 介绍过 OCI 有提供非阻塞的查询 API,除了创建连接和释放连接的环节,并且提供了一个接口可以暴露底层
socket 的文件描述符,这样我们就可以像 ngx_postgres [1] 和 ngx_drizzle [2]
模块那样把这个文件描述符注册到 nginx 的事件模型中去进行事件监听与调度,并实现 C10K. 当然,必需阻塞的操作需要借助于内部 OS
线程池这样的东西。

我已抄送给 chaoslawful 和 openresty 邮件列表 [3] 。

Best regards,
-agentzh

注:
[1] https://github.com/FRiCKLE/ngx_postgres
[2] http://wiki.nginx.org/HttpDrizzleModule
[3] http://groups.google.com/group/openresty

lhmwzy

unread,
Aug 11, 2012, 7:35:25 AM8/11/12
to Hui Yu, open...@googlegroups.com
这个对我来说是个好消息,能开发成功吗?

Chaos Wang

unread,
Aug 11, 2012, 8:23:30 AM8/11/12
to agentzh, Hui Yu, openresty
OCI 的 ognfd 可以获取到底层通信 fd,不过需要将建立成功的会话转换成 OCI
v7 的 LDA 结构才能调用该函数,例子如下:

sword fd;
Lda_Def lda;

OCIServerAttach(...);
OCISessionBegin(...);

// convert to OCI v7 LDA
OCISvcCtxToLda(svchp, envhp, &lda);
// get socket fd
ognfd(&lda, &fd);
// back to v8 svc
OCILdaToSvcCtx(&svchp, errhp, &lda);

在 OCIServerAttach 前可通过 OCIAttrSet 设置 server 句柄为非阻塞模式:

(void)OCIAttrSet((dvoid*)srvhp, OCI_HTYPE_SERVER, (dvoid*)0, (ub4)0,
OCI_ATTR_NONBLOCKING_MODE, errhp);

这样后续所有需要读取数据但未就绪的调用都会返回 OCI_STILL_EXECUTING 错
误,可以用上面获得的 fd 等待可读事件后在合适的时机重试。遗憾的
是,OCIServerAttach/OCISessionBegin/OCISessionEnd /OCISessionDetach 这几
步连接和会话建立和销毁调用不会受这个影响,它们仍然都是阻塞式的。故为了保
证对外服务正常,试图在 Nginx 中以非阻塞方式使用 OCI 必须自行维护一个线程
池专门委托处理连接、会话建立和销毁调用。

不过实际上比较棘手的问题是功能性的,OCI 客户端的 DRCP 机制提供了同服务侧
紧密结合的灾备、负载均衡和连接池管理功能,但该功能以独立线程实现且只能在
阻塞模式下工作,故应用一旦需要用到 DRCP 就没戏。考虑到这一不完美性,且
ngx_oracle 模块在淘宝内需求不大,就没有继续开发了……
Message has been deleted

Hui Yu

unread,
Aug 13, 2012, 1:20:53 AM8/13/12
to Chaos Wang, agentzh, openresty
引用“故应用一旦需要用到 DRCP 就没戏”

TAF是需要具备的,看来多线程是眼前比较可行的方案;

现在在查Protothreads库,看其在后期对优化上可有什么帮助?

在 12-8-11,Chaos Wang<chaos...@gmail.com> 写道:

lhmwzy

unread,
Sep 23, 2012, 8:51:34 PM9/23/12
to open...@googlegroups.com
目前开发进度如何了?

ganggewudi

unread,
Oct 9, 2012, 3:22:22 AM10/9/12
to open...@googlegroups.com, Hui Yu, 王晓哲
很多队列在lua中的使用都是阻塞的,我没找到非阻塞的lua的消息队列,另外,可以支持mysql吗

在 2012年8月11日星期六UTC+8上午10时33分59秒,agentzh写道:

agentzh

unread,
Oct 9, 2012, 1:58:00 PM10/9/12
to open...@googlegroups.com, Hui Yu, 王晓哲
Hello!

2012/10/9 ganggewudi:
> 很多队列在lua中的使用都是阻塞的,我没找到非阻塞的lua的消息队列,另外,可以支持mysql吗
>

可以看一下 Brian Akins 基于 ngx_lua cosocket 实现的这个 beanstalkd 队列的非阻塞客户端:

https://github.com/bakins/lua-resty-beanstalkd

当然,Redis 也是可以作为队列来使的,此时可以直接使用更为成熟的 lua-resty-redis 库:

https://github.com/agentzh/lua-resty-redis

同时,ngx_lua 支持 mysql 已经有多年了,有的用户通过 ngx.location.capture() 发起子请求访问 ngx_drizzle 模块:

http://wiki.nginx.org/HttpDrizzleModule

还有的用户直接使用 lua-resty-mysql 库:

https://github.com/agentzh/lua-resty-mysql

后者的功能更齐全一些,使用更方便一些。

Best regards,
-agentzh

ganggewudi

unread,
Oct 9, 2012, 9:58:34 PM10/9/12
to open...@googlegroups.com, Hui Yu, 王晓哲
bakins那个beanstalkd说明文档里面说这个队列非常不稳定,所以没敢在单位用,redis,可以单独写个脚本提取lua扔给redis内容吗?

在 2012年10月10日星期三UTC+8上午1时58分01秒,agentzh写道:
Reply all
Reply to author
Forward
0 new messages