How does nginx handle incomplete upstream writes
Maxim Dounin
mdounin at mdounin.ru
Wed Jun 27 03:57:03 UTC 2018
Hello!
On Mon, Jun 25, 2018 at 01:42:59PM -0400, scott.oaks at oracle.com wrote:
> I have a situation where when using nginx as a proxy, large POST
> requests to my upstream server sometimes fail -- for whatever reason
> (network congestion, upstream server paused for java GC. etc.), the
> initial writes fill up the socket buffers and so ngx_writev gets a
> EAGAIN. So that's pretty normal; I'd expect nginx to handle that, poll
> the fd, and retry the I/O when the socket is ready to write again. [In
> my case, that's always within a few seconds; if the socket isn't
> available within proxy_send_timeout, then I'd expect the request to be
> aborted.]
>
> Within the low-level parts of the nginx code, I see the framework for
> this all in place: ngx_writev() returns NGX_AGAIN to
> ngx_linux_sendfile_chain. That calls ngx_chain_update_sent to adjust the
> buffer for the amount written and marks the ngx event holder as not
> ready. Later, I do see nginx poll the fd; and the event holder gets
> marked as ready, but by that time the partially-written data has been
> lost and so is never written. Before that time, http_finalize_request
> has been called with a status of NGX_DONE on the call path back up from
> ngx_writev(), and the pending data seems also have been discarded.
> Interestingly, the call stack and path here seem to be the same whether
> proxy_request_buffering is on or off.
>
> Have I missed something ( must have, right?), or is the partial write
> situation just not handled properly at all?
It is properly handled. Buffers not yet written to the socket are
referenced by ngx_chain_writer() in ctx->out and nginx will try to
sent them again once the socket is ready for writing.
[...]
> proxy_send_timeout). That blocks the worker for that time, but the
> worker can really only handle one request at a time anyway, correct?
No. Each worker can handle thousands of active requests by
switching between them as sockets are ready for reading or
writing. Blocking nginx worker is a bad idea, as this block all
requests.
--
Maxim Dounin
http://mdounin.ru/
More information about the nginx-devel
mailing list