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é