How to write async http web client inside nginx code?

瀏覽次數:4,559 次
跳到第一則未讀訊息

Ajay Bodhe

未讀,
2014年8月12日 下午1:35:292014/8/12
收件者:openre...@googlegroups.com
I am writing an application server whose code will be written as Nginx/Openresty module (c/c++). This server is supposed to send HTTP Requests to other servers & wait for response from them for 200-400ms.

If I use libcurl to make http calls then the single thread of Nginx/Openresty will be blocked & event loop will not accept further requests.

If I use some non blocking Libs like ASIO/LibUV then there will be two event loops running?

How this problem of Async IO/Network-Req can be solved when code is written as Nginx/Openresty Module?

Yichun Zhang (agentzh)

未讀,
2014年8月12日 下午2:31:072014/8/12
收件者:openresty-en
Hello!

On Tue, Aug 12, 2014 at 10:35 AM, Ajay Bodhe wrote:
> I am writing an application server whose code will be written as
> Nginx/Openresty module (c/c++). This server is supposed to send HTTP
> Requests to other servers & wait for response from them for 200-400ms.
>

You should use ngx_lua's cosocket API for such things:

https://github.com/openresty/lua-nginx-module#ngxsockettcp

For example, James Hurst's lua-resty-http is an HTTP client library
based on ngx_lua's cosockets:

https://github.com/pintsized/lua-resty-http

Alternatively you can use nginx subrequests via ngx.location.capture()
with the standard ngx_proxy module to do upstream HTTP communication,
which is also nonblocking.

> If I use libcurl to make http calls then the single thread of
> Nginx/Openresty will be blocked & event loop will not accept further
> requests.
>

libcurl should always be avoided in the context of nginx due to its
blocking effect, no matter which language you're using.

> If I use some non blocking Libs like ASIO/LibUV then there will be two event
> loops running?
>

Yes, of course. You have to use the nginx event loop, just as
ngx_lua's cosocket API or the subrequest/ngx_proxy approach.

> How this problem of Async IO/Network-Req can be solved when code is written
> as Nginx/Openresty Module?
>

Coding up an nginx pure C module for this is usually much harder than
using the Lua-land cosockets or subrequest APIs while without much
real gain if you're doing complicated business logic inside nginx.

Regards,
-agentzh

Ajay Bodhe

未讀,
2014年8月13日 凌晨2:54:292014/8/13
收件者:openre...@googlegroups.com
Hi,


Coding up an nginx pure C module for this is usually much harder than
using the Lua-land cosockets or subrequest APIs while without much
real gain if you're doing complicated business logic inside nginx.


I did not get this while part exactly.

I am building a server with some flow will ask the question on different thread. Hope not bothering you much.
Appreciate the help.

Aapo Talvensaari

未讀,
2014年8月13日 清晨7:03:072014/8/13
收件者:openre...@googlegroups.com
You should use ngx_lua's cosocket API for such things:

    https://github.com/openresty/lua-nginx-module#ngxsockettcp

For example, James Hurst's lua-resty-http is an HTTP client library
based on ngx_lua's cosockets:

    https://github.com/pintsized/lua-resty-http

Alternatively you can use nginx subrequests via ngx.location.capture()
with the standard ngx_proxy module to do upstream HTTP communication,
which is also nonblocking.

I'm curious to know what kind of performance difference there would be with ngx.location.capture/proxy vs. say lua-resty-http. I kinda like that with proxy you can configure this and that easily in Nginx config (http://nginx.org/en/docs/http/ngx_http_proxy_module.html). And as it's on the core of Nginx, the quality will be really good (it's so essential in nginx architecture). That's why I have been thinking about trying to make some small http-lib in Lua that utilizes this proxy thing (with internal locations) for actual requests.


Regards
Aapo

Aapo Talvensaari

未讀,
2014年8月13日 上午8:11:592014/8/13
收件者:openre...@googlegroups.com
Or make it upside down. Could proxy functions and configuration be provided on Lua side as well? I.e. you could call ngx.proxy_pass(url) (or do we need proxy_by_lua / proxy_by_lua_file as well then)?


Regards
Aapo

Hamish Forbes

未讀,
2014年8月13日 上午8:16:182014/8/13
收件者:openre...@googlegroups.com
I did some fairly basic performance testing of lua-resty-http and the nginx proxy module a while back.
Just using ab to hammer another machine running openresty that proxied to a 3rd which served a 25KB static file.

There was essentially no difference between the 2 methods, in fact my testing showed a tiny advantage to lua-resty-http but it was small enough to be within the margin of error.

The big advantage of using a Lua http client rather than the sub-requests within Lua is the ability to stream both the request body and the response in chunks.
If you have to buffer those both into memory you are a) using a lot more memory than needed b) wasting time by having to wait for the entire request / response before passing it on.

In short using lua-resty-http or pure nginx proxy module (no Lua) is about the same, but using ngx.location.capture and the nginx proxy module will incur memory and latency penalties at the very least.

Yichun Zhang (agentzh)

未讀,
2014年8月13日 下午4:09:582014/8/13
收件者:openresty-en
Hello!

On Wed, Aug 13, 2014 at 4:03 AM, Aapo Talvensaari wrote:
> I kinda like that with
> proxy you can configure this and that easily in Nginx config
> (http://nginx.org/en/docs/http/ngx_http_proxy_module.html).

Well, you can also configure things in Lua, as in

https://github.com/openresty/lua-resty-upstream-healthcheck#synopsis

And yeah, it's kinda ugly due to the escaping things. I'm going to
implement a Lua block for ngx_lua, such that we can get rid of those
ugly escaping gotchas, as in

content_by_lua_block {
ngx.say("hello world\r\n")
}

which is equivalent to

content_by_lua "
ngx.say("hello world\\r\\n")
";

Essentially there is an interleaving Lua parser in the nginx config
file parser ;)

> And as it's on
> the core of Nginx, the quality will be really good (it's so essential in
> nginx architecture).

Just to be clear, the ngx_lua's cosocket implementation is essentially
the same as the ngx_http_upstream mechanism used by ngx_proxy on the C
level, but the former is specifically designed to be more general and
more flexible :)

We can even get more speed from the existing lua-resty-* client
libraries by actually JITting the cosocket API in the near future :)
Right now the cosocket part is always interpreted even by LuaJIT (due
to its use of the classic lua_CFunction API).

> That's why I have been thinking about trying to make
> some small http-lib in Lua that utilizes this proxy thing (with internal
> locations) for actual requests.
>

IMHO, the subrequest route is a dead end due to the limited
implementation in the nginx core. For example, it's VERY hard to do
streaming processing with a subrequest or aborting a running
subrequest safely without terminating the whole main request. I
already have no plan to add fancy features to the existing subrequest
API but I'll still maintain this thing to ensure it works as specified
:)

Also, communicating with general nginx C modules without special
optimizations for ngx_lua is somewhat inefficient per se (i.e.,
through nginx variables or subrequest interfaces).

Best regards,
-agentzh

hqzha...@gmail.com

未讀,
2016年3月2日 凌晨3:00:382016/3/2
收件者:openresty-en
https://github.com/gogofly/remote-server-control-module
This is my pure C module solution.

在 2014年8月13日星期三 UTC+8上午2:31:07,agentzh写道:

Nithish Reddy

未讀,
2017年11月16日 凌晨4:18:572017/11/16
收件者:openresty-en
Hi, 
 i am also trying to use lua-resty-http library with nignx.

content_by_lua_block code is not executing.

Actual my problem statement is : For every request coming in to nginx server, i have to call "A" server based on response i will decide to which server i have to forward that incoming reuqest.??

in nginx.conf:

location /test {
 content_by_lua_block {
                ngx.req.read_body ()
                local args, err = ngx.req.get_uri_args ()

                local http = require "resty.http"
                 local httpc = http.new ()
                 local res, err = httpc: request_uri (
                    "https://127.0.0.1/module/Page/test",
                        {
                        method = "POST" ,
                         body = args.data,
                      }
                )
                }
}
Any help ??

-- Nithish Reddy

Rohit Atri

未讀,
2018年8月2日 凌晨2:10:352018/8/2
收件者:openresty-en
IMHO, the subrequest route is a dead end due to the limited
implementation in the nginx core.
Is this still the case? :-)
回覆所有人
回覆作者
轉寄
0 則新訊息