Le lundi 27 décembre 2010 07:10:37, Willy Tarreau a écrit :
> It's nice that you managed to reproduce it ! I'm not sure how you managed
> to get it though because you're saying that you have it with and without
> nginx.

Oh sorry, I thought it was clear enough with the first mail.
Ok, here is the full test.

nginx is in front of haproxy with this configuration :
events {
        worker_connections 1000;
}

http {
        server {
                listen 8080;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                location /httpclose {
                        proxy_pass http://127.0.0.1:8081;
                } 
                location /tunnel {
                        proxy_pass http://127.0.0.1:8082;
                } 
                location /forceclose {
                        proxy_pass http://127.0.0.1:8083;
                } 
        }
}

haproxy is run with :
listen httpclose_test :8081
        mode http
        option httpclose
        option http-pretend-keepalive
        server www localhost:80

listen tunnel_test :8082
        mode http
        option http-pretend-keepalive
        server www localhost:80

listen forceclose_test :8083
        mode http
        option forceclose
        option http-pretend-keepalive
        server www localhost:80

The backend is apache with KeepAliveTimeout 15.

Now some results :

* TEST 1 with "option httpclose" and "option http-pretend-keepalive"

$ time curl -i http://localhost:8080/httpclose
HTTP/1.1 404 Not Found
Server: nginx/0.8.53
Date: Mon, 27 Dec 2010 17:20:56 GMT
Content-Type: text/html; charset=iso-8859-1
Connection: keep-alive
Vary: Accept-Encoding
Content-Length: 282

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /httpclose was not found on this server.</p>
<hr>
<address>Apache/2.2.16 (Ubuntu) Server at localhost Port 80</address>
</body></html>

real    0m15.027s
user    0m0.008s
sys     0m0.000s

During this test, the haproxy debug is :
00000000:httpclose_test.accept(0004)=0007 from [127.0.0.1:42571]
00000000:httpclose_test.clireq[0007:ffff]: GET /httpclose HTTP/1.0
00000000:httpclose_test.clihdr[0007:ffff]: Host: localhost
00000000:httpclose_test.clihdr[0007:ffff]: X-Real-IP: 127.0.0.1
00000000:httpclose_test.clihdr[0007:ffff]: X-Forwarded-For: 127.0.0.1
00000000:httpclose_test.clihdr[0007:ffff]: Connection: close
00000000:httpclose_test.clihdr[0007:ffff]: User-Agent: curl/7.21.2 (i686-pc-
linux-gnu) libcurl/7.21.2 OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.18
00000000:httpclose_test.clihdr[0007:ffff]: Accept: */*
00000000:httpclose_test.srvrep[0007:0008]: HTTP/1.1 404 Not Found
00000000:httpclose_test.srvhdr[0007:0008]: Date: Mon, 27 Dec 2010 17:14:01 GMT
00000000:httpclose_test.srvhdr[0007:0008]: Server: Apache/2.2.16 (Ubuntu)
00000000:httpclose_test.srvhdr[0007:0008]: Vary: Accept-Encoding
00000000:httpclose_test.srvhdr[0007:0008]: Content-Length: 282
00000000:httpclose_test.srvhdr[0007:0008]: Keep-Alive: timeout=15, max=100
00000000:httpclose_test.srvhdr[0007:0008]: Connection: Keep-Alive
00000000:httpclose_test.srvhdr[0007:0008]: Content-Type: text/html; 
charset=iso-8859-1
00000000:httpclose_test.srvcls[0007:0008]
00000000:httpclose_test.clicls[0007:0008]
00000000:httpclose_test.closed[0007:0008]

* TEST 2 with only "option http-pretend-keepalive"

$ time curl -i http://localhost:8080/tunnel
HTTP/1.1 404 Not Found
Server: nginx/0.8.53
Date: Mon, 27 Dec 2010 17:24:57 GMT
Content-Type: text/html; charset=iso-8859-1
Connection: keep-alive
Vary: Accept-Encoding
Content-Length: 279

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /tunnel was not found on this server.</p>
<hr>
<address>Apache/2.2.16 (Ubuntu) Server at localhost Port 80</address>
</body></html>

real    0m15.024s
user    0m0.012s
sys     0m0.000s

haproxy debug :
00000001:tunnel_test.accept(0005)=0007 from [127.0.0.1:33892]
00000001:tunnel_test.clireq[0007:ffff]: GET /tunnel HTTP/1.0
00000001:tunnel_test.clihdr[0007:ffff]: Host: localhost
00000001:tunnel_test.clihdr[0007:ffff]: X-Real-IP: 127.0.0.1
00000001:tunnel_test.clihdr[0007:ffff]: X-Forwarded-For: 127.0.0.1
00000001:tunnel_test.clihdr[0007:ffff]: Connection: close
00000001:tunnel_test.clihdr[0007:ffff]: User-Agent: curl/7.21.2 (i686-pc-linux-
gnu) libcurl/7.21.2 OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.18
00000001:tunnel_test.clihdr[0007:ffff]: Accept: */*
00000001:tunnel_test.srvrep[0007:0008]: HTTP/1.1 404 Not Found
00000001:tunnel_test.srvhdr[0007:0008]: Date: Mon, 27 Dec 2010 17:24:57 GMT
00000001:tunnel_test.srvhdr[0007:0008]: Server: Apache/2.2.16 (Ubuntu)
00000001:tunnel_test.srvhdr[0007:0008]: Vary: Accept-Encoding
00000001:tunnel_test.srvhdr[0007:0008]: Content-Length: 279
00000001:tunnel_test.srvhdr[0007:0008]: Keep-Alive: timeout=15, max=100
00000001:tunnel_test.srvhdr[0007:0008]: Connection: Keep-Alive
00000001:tunnel_test.srvhdr[0007:0008]: Content-Type: text/html; 
charset=iso-8859-1
00000001:tunnel_test.srvcls[0007:0008]
00000001:tunnel_test.clicls[0007:0008]
00000001:tunnel_test.closed[0007:0008]

* TEST 3 with "option forceclose" and "option http-pretend-keepalive"

$ time curl -i http://localhost:8080/forceclose
HTTP/1.1 404 Not Found
Server: nginx/0.8.53
Date: Mon, 27 Dec 2010 17:28:53 GMT
Content-Type: text/html; charset=iso-8859-1
Connection: keep-alive
Vary: Accept-Encoding
Content-Length: 283

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /forceclose was not found on this server.</p>
<hr>
<address>Apache/2.2.16 (Ubuntu) Server at localhost Port 80</address>
</body></html>

real    0m0.012s
user    0m0.000s
sys     0m0.008s

haproxy debug :
00000002:forceclose_test.accept(0006)=0007 from [127.0.0.1:33795]
00000002:forceclose_test.clireq[0007:ffff]: GET /forceclose HTTP/1.0
00000002:forceclose_test.clihdr[0007:ffff]: Host: localhost
00000002:forceclose_test.clihdr[0007:ffff]: X-Real-IP: 127.0.0.1
00000002:forceclose_test.clihdr[0007:ffff]: X-Forwarded-For: 127.0.0.1
00000002:forceclose_test.clihdr[0007:ffff]: Connection: close
00000002:forceclose_test.clihdr[0007:ffff]: User-Agent: curl/7.21.2 (i686-pc-
linux-gnu) libcurl/7.21.2 OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.18
00000002:forceclose_test.clihdr[0007:ffff]: Accept: */*
00000002:forceclose_test.srvrep[0007:0008]: HTTP/1.1 404 Not Found
00000002:forceclose_test.srvhdr[0007:0008]: Date: Mon, 27 Dec 2010 17:28:53 
GMT
00000002:forceclose_test.srvhdr[0007:0008]: Server: Apache/2.2.16 (Ubuntu)
00000002:forceclose_test.srvhdr[0007:0008]: Vary: Accept-Encoding
00000002:forceclose_test.srvhdr[0007:0008]: Content-Length: 283
00000002:forceclose_test.srvhdr[0007:0008]: Keep-Alive: timeout=15, max=100
00000002:forceclose_test.srvhdr[0007:0008]: Connection: Keep-Alive
00000002:forceclose_test.srvhdr[0007:0008]: Content-Type: text/html; 
charset=iso-8859-1
00000002:forceclose_test.srvcls[0007:0008]
00000002:forceclose_test.clicls[0007:0008]
00000002:forceclose_test.closed[0007:0008]

(Note that when disabling proxy buffering in nginx, the 15s delay is fixed).

Now, I can also observe the same behaviour using ab directly on haproxy :
$ ab http://localhost:8081/
=> 15s delay

$ ab http://localhost:8082/
=> 15s delay

$ ab http://localhost:8083/
=> immediate response

> [ I unwrapped your patch because apparently your mailer did not like it ]

Yes sorry for that, I'm thinking of changing my mailer :-/

> >    ((s->fe->options2 & PR_O2_FAKE_KA) != (s->be->options & >
> > PR_O2_FAKE_KA))) {
> 
>                                                                 ^^^
> Here above it should be "options2".

Oops, fixed in my code.

> I must say I'm having difficulties to understand the logics. The rule is
> becoming quite complex, so we should probably first try to define how
> we'd like pretend-keep-alive to work in various cases.

Same here, maybe it should/can be simplified in the 1.5 branch (or future 1.6).
And i fear it will become more and more complex the day haproxy supports 
client side keep-alive (if it will).
Due to this complexity, I really wanted a second look...which was needed (the 
typo in the variable name confirmed it :-)).

> In my opinion, this option's goal is to make a server think we're sending
> it a keep-alive request so that it can announce a valid content-length or
> chunking to the client, eventhough we intend to close its connection. So
> what I'm thinking is that this option should only be considered if either
> "httpclose", "forceclose" or "http-server-close" is enabled in either the
> frontend or backend, or if the request indicates a close.
> 
> I also think that if we have httpclose (or the request indicated a close)
> with the option set, then we can assume the server will not close after
> its response, which can make the client wait for a timeout. Thus, we should
> probably turn the response to a forced close in this case.
> 
> Do you agree with that ? Is it what you wanted to do ?

I agree. You precisely explained what I tried to fix.

> Do you see any other case that must be covered ?

I only see the "tunnel mode" case, where http-pretend-keepalive also 
introduces this timeout side effect. With this patch, a forced close is applied 
in that case too.

If it's ok for you, I'll resend the updated patch in a correct way.

-- 
Cyril Bonté

Reply via email to