Nginx Proxy seems to send twice the same request to the backend
Maxim Dounin
mdounin at mdounin.ru
Mon Jul 10 13:49:35 UTC 2017
Hello!
On Sun, Jul 09, 2017 at 11:26:47PM +0200, Arnaud Le-roy wrote:
> i encountered a strange behaviour with nginx, my backend seems
> to receive twice the same request from nginx proxy, to be sure
> that it's not the client that send two request i have had an
> uuid params to each request.
>
> when the problem occurs in nginx log i found one request in
> success in access.log
>
> x.x.x.x - - [09/Jul/2017:09:18:33 +0200] "GET /query?uid=b85cc8a4-b9cd-4093-aea5-95c0ea1391a6_428 HTTP/1.1" 200 2 "-" "-"
>
> and an other one than generate this log in error.log :
>
> 2017/07/09 09:18:31 [error] 38111#38111: *4098505 upstream prematurely closed connection while reading response header from upstream, client: x.x.x.x, server: x.x.com, request: "GET /query?uid=b85cc8a4-b9cd-4093-aea5-95c0ea1391a6_428 HTTP/1.1", upstream: "http://172.16.0.11:9092/query?uid=b85cc8a4-b9cd-4093-aea5-95c0ea1391a6_428", host: "x.x.com"
>
> on my backend i can see two request with the same uuid (the two
> succeed)
>
> {"pid":11424,"level":"info","message":"[API] AUTH1 /query?uid=b85cc8a4-b9cd-4093-aea5-95c0ea1391a6_428","timestamp":"2017-07-09 09:18:31.861Z"}
> {"pid":11424,"level":"info","message":"[API] AUTH1 /query?uid=b85cc8a4-b9cd-4093-aea5-95c0ea1391a6_428","timestamp":"2017-07-09 09:18:33.196Z"}
>
> The client is a node program so i'm sure that it sends only one
> request with the same uuid (no thread problem ;) the nginx serve
> as simple proxy (no load balancing)
[...]
> upstream api {
> keepalive 100;
> server 172.16.0.11:9092;
> }
[...]
> location / {
> proxy_next_upstream off;
> proxy_pass http://api;
[...]
> The backend is a simple node server.
>
> the problem occurs randomly, and it happens for sure on
> nginx/1.10.3 and nginx/1.13.2 on debian/jessie
>
> After some days of research, i found that if i remove the
> keepalive 100 from upstream configuration there is no longer the
> problem but i don't understand why ? Maybe somebody can explain
> me what could hapen ? maybe a misunderstanding about some
> configuration on keep alive ?
With keepalive connections, it is possible that server will close
the connection and the client will start sending a request a the
same time. This case is specifically outlined in RFC 2616,
https://tools.ietf.org/html/rfc2616#section-8.1.4
A client, server, or proxy MAY close the transport connection at any
time. For example, a client might have started to send a new request
at the same time that the server has decided to close the "idle"
connection. From the server's point of view, the connection is being
closed while it was idle, but from the client's point of view, a
request is in progress.
This means that clients, servers, and proxies MUST be able to recover
from asynchronous close events. Client software SHOULD reopen the
transport connection and retransmit the aborted sequence of requests
without user interaction so long as the request sequence is
idempotent (see section 9.1.2).
In such situation nginx will re-try the request, as suggested by
the standard. In nginx before 1.9.13 this happened even with
"proxy_next_upstream off".
Though in nginx 1.9.13 this code was rewritten as part of the
introduction of non-idempotent methods handling in
proxy_next_upstream. And in nginx 1.9.13+ re-trying the request
is not expected to happen unless "proxy_next_upstream error" is
also configured. As such, the exact configuration looks strange
combined with the versions you claim.
Could you please double-check that the behaviour you describe
appears when using nginx 1.13.2 and with proxy_next_upstream
switched off?
Just in case, I've tested it here using the following simple nginx
configuration:
upstream foo {
server 127.0.0.1:8081;
keepalive 10;
}
server {
listen 8080;
location / {
proxy_pass http://foo;
proxy_set_header Connection "";
proxy_http_version 1.1;
proxy_next_upstream off;
}
}
server {
listen 8081;
if ($connection_requests ~ 2) {
return 444;
}
return 200 ok;
}
As expected, it returns 502 when using "proxy_next_upstream off"
and re-tries the request if proxy_next_upstream is not switched
off.
Note well that if duplicate requests introduce a problem, you may
want to reconsider logic of your backend. At least idempotent
requests can be freely retried, and your backend is expected to
handle this. (In practice this often happens even with
non-idempotent requests too.)
--
Maxim Dounin
http://nginx.org/
More information about the nginx
mailing list