[PATCH] HTTP: trigger lingering close when keepalive connection will be closed

Sergey Kandaurov pluknet at nginx.com
Thu Feb 2 14:53:20 UTC 2023


> On 27 Jan 2023, at 08:01, Maxim Dounin <mdounin at mdounin.ru> wrote:
> 
> Hello!
> 
> [..]
> Overall, after looking into logs and tcpdump you've provided I 
> tend to think that the only working fix would be to introduce 
> c->pipeline flag, and force lingering close if there were any 
> pipelined requests on the connection.
> 
> Below is the patch which implements this approach.  Review and 
> testing appreciated.  It can be used either separately or with the 
> previously provided patch to use posted next events.
> 
> # HG changeset patch
> # User Maxim Dounin <mdounin at mdounin.ru>
> # Date 1674790916 -10800
> #      Fri Jan 27 06:41:56 2023 +0300
> # Node ID 784d0fa0b5a0796561642a5a64dc4e9e07592852
> # Parent  4eb1383f6432b034630e6de18739b817f6565c8c
> Lingering close for connections with pipelined requests.
> 
> This is expected to help with clients using pipelining with some constant
> depth, such as apt[1][2].
> 
> When downloading many resources, apt uses pipelining with some constant
> depth, a number of requests in flight[1][2].  This essentially means that

Are links repeated on purpose?

> after receiving a response it sends an additional request to the server,
> and this can result in requests arriving to the server at any time.  Further,
> additional requests are sent one-by-one, and can be easily seen as such
> (neither as pipelined, nor followed by pipelined requests).
> 
> The only safe approach to close such connections (for example, when
> keepalive_requests is reached) is with lingering.  To do so, now nginx
> monitors if pipelining was used on the connection, and if it was, closes
> the connection with lingering.
> 
> [1] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=973861#10
> [2] https://mailman.nginx.org/pipermail/nginx-devel/2023-January/ZA2SP5SJU55LHEBCJMFDB2AZVELRLTHI.html
> 
> diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h
> --- a/src/core/ngx_connection.h
> +++ b/src/core/ngx_connection.h
> @@ -172,6 +172,7 @@ struct ngx_connection_s {
>     unsigned            timedout:1;
>     unsigned            error:1;
>     unsigned            destroyed:1;
> +    unsigned            pipeline:1;
> 
>     unsigned            idle:1;
>     unsigned            reusable:1;
> diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
> --- a/src/http/ngx_http_request.c
> +++ b/src/http/ngx_http_request.c
> @@ -2753,7 +2753,8 @@ ngx_http_finalize_connection(ngx_http_re
>         || (clcf->lingering_close == NGX_HTTP_LINGERING_ON
>             && (r->lingering_close
>                 || r->header_in->pos < r->header_in->last
> -                || r->connection->read->ready)))
> +                || r->connection->read->ready
> +                || r->connection->pipeline)))
>     {
>         ngx_http_set_lingering_close(r->connection);
>         return;
> @@ -3123,6 +3124,7 @@ ngx_http_set_keepalive(ngx_http_request_
> 
>         c->sent = 0;
>         c->destroyed = 0;
> +        c->pipeline = 1;
> 
>         if (rev->timer_set) {
>             ngx_del_timer(rev);
> 

Looks good to me.

Further, as request pipelining implementation status is quite limited
(often disabled by default or unimplemented, notably in browsers),
I believe the change is fine to not cause noticeable legit resource usage.
Still, old behaviour can be reverted with "lingering_close off;".

-- 
Sergey Kandaurov


More information about the nginx-devel mailing list