Re: abortonclose for established connections?

2015-04-27 Thread Willy Tarreau
Hi Ludovico,

On Mon, Apr 27, 2015 at 10:54:43AM -0700, Ludovico Cavedon wrote:
> Hi Willy,
> 
> On Wed, Apr 22, 2015 at 10:58 AM, Ludovico Cavedon 
> wrote:
> 
> > I will let you know, thanks again!
> >
> >
> I reproduced your test case and it turned out the abortonclose option was
> only in the listener section (and not on backend/defautls).
> I moved it to "defaults" and now haproxy is behaving as expected.

Great! Thanks for your feedback!

Cheers,
Willy




Re: abortonclose for established connections?

2015-04-27 Thread Ludovico Cavedon
Hi Willy,

On Wed, Apr 22, 2015 at 10:58 AM, Ludovico Cavedon 
wrote:

> I will let you know, thanks again!
>
>
I reproduced your test case and it turned out the abortonclose option was
only in the listener section (and not on backend/defautls).
I moved it to "defaults" and now haproxy is behaving as expected.

Thanks for your help!
Ludovico


Re: abortonclose for established connections?

2015-04-22 Thread Ludovico Cavedon
Hi Willy,

thank you for the very detailed information.

On Wed, Apr 22, 2015 at 8:57 AM, Willy Tarreau  wrote:

> That's normal, this is httpterm and it doesn't monitor the connection while
> it's waiting. But in your case it should definitely work. Or it means that
> your server ignores the client abort. It would be nice if you could double-
> check this.
>

This could very well be the case. I will check and let you know.

If your server does indeed not support client-abort, then there's a
> workaround. Haproxy 1.5 supports half-closed timeouts. You can simply
> add a directive "timeout server-fin 1s" and it will automatically close
> the server connection 1 second after sending it the close if the server
> doesn't respond (and then report a server error) :
>

My server is nginx, I will see if I can configure it to "abortonclose" as
well. Otherwise the server-fin option looks viable.

I suspect it could match your needs if the normal solution doesn't work.
> This *does* require abortonclose since you want the shutdown() to have been
> done first. Please keep us updated.
>

I will let you know, thanks again!

Ludovico


Re: abortonclose for established connections?

2015-04-22 Thread Willy Tarreau
Hi again Ludovico,

so I ran some tests here with latest 1.5. I telnet to haproxy, send
"GET /?t=1 HTTP/1.1" then quit. It forwards to a server which
waits 10s before responding.

First, without "option abortonclose" :

17:47:40.174784 accept4(7, {sa_family=AF_INET, sin_port=htons(53833), 
sin_addr=inet_addr("127.0.0.1")}, [16], SOCK_NONBLOCK) = 12
17:47:40.174879 setsockopt(12, SOL_TCP, TCP_NODELAY, [1], 4) = 0
17:47:40.174927 accept4(7, 0x7fff89a6c8d0, [128], SOCK_NONBLOCK) = -1 EAGAIN 
(Resource temporarily unavailable)
17:47:40.174994 recvfrom(12, 0x743234, 7000, 0, 0, 0) = -1 EAGAIN (Resource 
temporarily unavailable)
17:47:40.175043 epoll_ctl(3, EPOLL_CTL_ADD, 12, {EPOLLIN|0x2000, {u32=12, 
u64=12}}) = 0
17:47:40.175075 epoll_wait(3, {}, 200, 1000) = 0
17:47:41.176196 epoll_wait(3, {}, 200, 1000) = 0
17:47:42.177325 epoll_wait(3, {}, 200, 1000) = 0
17:47:43.178458 epoll_wait(3, {{EPOLLIN, {u32=12, u64=12}}}, 200, 1000) = 1
17:47:44.071505 recvfrom(12, "GET /?t=1 HTTP/1.1\r\n", 7000, 0, NULL, NULL) 
= 24
17:47:44.071564 setsockopt(12, SOL_TCP, TCP_QUICKACK, [1], 4) = 0
17:47:44.071612 epoll_wait(3, {{EPOLLIN, {u32=12, u64=12}}}, 200, 1000) = 1
17:47:44.411719 recvfrom(12, "\r\n", 6976, 0, NULL, NULL) = 2
17:47:44.411809 socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 13
17:47:44.411841 fcntl(13, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
17:47:44.411864 setsockopt(13, SOL_TCP, TCP_NODELAY, [1], 4) = 0
17:47:44.411891 connect(13, {sa_family=AF_INET, sin_port=htons(8080), 
sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in 
progress)
17:47:44.411969 epoll_wait(3, {}, 200, 0) = 0
17:47:44.411998 sendto(13, "GET /?t=1 HTTP/1.1\r\n\r\n", 26, 
MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 26
17:47:44.412047 epoll_wait(3, {}, 200, 0) = 0
17:47:44.412071 recvfrom(13, 0x745224, 7000, 0, 0, 0) = -1 EAGAIN (Resource 
temporarily unavailable)
17:47:44.412096 epoll_ctl(3, EPOLL_CTL_ADD, 13, {EPOLLIN|0x2000, {u32=13, 
u64=13}}) = 0
17:47:44.412121 epoll_wait(3, {}, 200, 1000) = 0
17:47:45.413235 epoll_wait(3, {{EPOLLIN|0x2000, {u32=12, u64=12}}}, 200, 1000) 
= 1
17:47:46.288142 recvfrom(12, "", 7000, 0, NULL, NULL) = 0

=> the close was received

17:47:46.288210 epoll_ctl(3, EPOLL_CTL_DEL, 12, {0, {u32=12, u64=12}}) = 0
17:47:46.288242 epoll_wait(3, {}, 200, 1000) = 0
17:47:47.289369 epoll_wait(3, {}, 200, 1000) = 0

... but not forwarded, as expected.

Now with "option abortonclose" :

17:50:30.406154 accept4(7, {sa_family=AF_INET, sin_port=htons(53838), 
sin_addr=inet_addr("127.0.0.1")}, [16], SOCK_NONBLOCK) = 12
17:50:30.406247 setsockopt(12, SOL_TCP, TCP_NODELAY, [1], 4) = 0
17:50:30.406297 accept4(7, 0x7fff407d3740, [128], SOCK_NONBLOCK) = -1 EAGAIN 
(Resource temporarily unavailable)
17:50:30.406352 recvfrom(12, 0x743234, 7000, 0, 0, 0) = -1 EAGAIN (Resource 
temporarily unavailable)
17:50:30.406415 epoll_ctl(3, EPOLL_CTL_ADD, 12, {EPOLLIN|0x2000, {u32=12, 
u64=12}}) = 0
17:50:30.406444 epoll_wait(3, {}, 200, 1000) = 0
17:50:31.407562 epoll_wait(3, {}, 200, 1000) = 0
17:50:32.408696 epoll_wait(3, {}, 200, 1000) = 0
17:50:33.409768 epoll_wait(3, {{EPOLLIN, {u32=12, u64=12}}}, 200, 1000) = 1
17:50:33.451660 recvfrom(12, "GET /?t=1 HTTP/1.1\r\n", 7000, 0, NULL, NULL) 
= 24
17:50:33.451715 setsockopt(12, SOL_TCP, TCP_QUICKACK, [1], 4) = 0
17:50:33.451762 epoll_wait(3, {{EPOLLIN, {u32=12, u64=12}}}, 200, 1000) = 1
17:50:33.736088 recvfrom(12, "\r\n", 6976, 0, NULL, NULL) = 2
17:50:33.736186 socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 13
17:50:33.736222 fcntl(13, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
17:50:33.736246 setsockopt(13, SOL_TCP, TCP_NODELAY, [1], 4) = 0
17:50:33.736272 connect(13, {sa_family=AF_INET, sin_port=htons(8080), 
sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in 
progress)
17:50:33.736349 epoll_wait(3, {}, 200, 0) = 0
17:50:33.736378 sendto(13, "GET /?t=1 HTTP/1.1\r\n\r\n", 26, 
MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 26
17:50:33.736427 epoll_wait(3, {}, 200, 0) = 0
17:50:33.736451 recvfrom(13, 0x745224, 7000, 0, 0, 0) = -1 EAGAIN (Resource 
temporarily unavailable)
17:50:33.736475 epoll_ctl(3, EPOLL_CTL_ADD, 13, {EPOLLIN|0x2000, {u32=13, 
u64=13}}) = 0
17:50:33.736500 epoll_wait(3, {{EPOLLIN|0x2000, {u32=12, u64=12}}}, 200, 1000) 
= 1
17:50:34.378879 recvfrom(12, "", 7000, 0, NULL, NULL) = 0

==> close was received

17:50:34.378929 shutdown(13, 1 /* send */) = 0

==> and immediately forwarded.

17:50:34.378992 epoll_ctl(3, EPOLL_CTL_DEL, 12, {0, {u32=12, u64=12}}) = 0
17:50:34.379043 epoll_wait(3, {}, 200, 1000) = 0
17:50:35.380170 epoll_wait(3, {}, 200, 1000) = 0
17:50:36.381305 epoll_wait(3, {}, 200, 1000) = 0

==> the server didn't consider it, as is confirmed here :

$ netstat -atn|grep CLO
tcp0  0 127.0.0.1:8080  127.0.0.1:36255 CLOSE_WAIT 
tcp0  0 127.0.0.1:18080 127.0.0.1:53838 CLOSE_WAIT 

That's normal, this is httpterm and it doesn't monitor the connection while
it's waiting. But in your cas

Re: abortonclose for established connections?

2015-04-21 Thread Willy Tarreau
Hi Ludovico,

On Fri, Apr 17, 2015 at 08:24:43PM -0700, Ludovico Cavedon wrote:
> Hi,
> 
> I am trying to find a solution to the following issue.
> 
> I have a client A that sends hundreds of HTTP requests per second to
> server B running ha-proxy 1.5.3.
> Server B/haproxy forwards them to server C.
> 
> Some of these request are long-polling: server C will receive the
> request and hang for a very long time (even hours potentially).
> Client A may decide to give up on long-polling request, close the
> connection and forget about it.
> However, haproxy will keep the connection state half-open, assuming
> the client is still there waiting for data.
> 
> On client A the connection state will go to FIN_WAIT2, and will be
> forgotten after 60 seconds.
> 
> After a while, client A will happen reuse the source port for a new
> connection, and send a SYN packet. On server B, however, the
> connection is still there in CLOSE_WAIT.
> 
> I am trying to find a way to avoid this from happening. Ideally I
> would like haproxy to close the connection completely if the client
> closes its side.
> "abortonclose" seemed the right option, but it looks like it works
> only if the FIN arrives before the connection to server C has not been
> established yet.
> 
> The statement from [1] sounded promising:
> > In 1.5 we have even improved that a bit further for users of long-polling
> > requests. When "option abortonclose" is set, if the client closes the send
> > side, then haproxy forwards this closing event to the server.
> 
> however it does not seem to happen in my case.
> 
> What am I doing wrong? Does it have to do with the fact that
> connection to server C are reused/persistent?
> Is there maybe a way to tell haproxy to close the client connection if
> there is no keepalive?

You're not necessarily doing anything wrong, it's fairly possible there's
a bug or an inconsistency between multiple options. I'll have to retry
here with your config, because the statement you quoted indeed indicates
that we should get a better behaviour. I won't do it immediately because
I'm still stuck fixing the things I recently broke before merging that
into 1.6.

In the mean time I would appreciate it if you could retry with 1.5.11 to
verify if you see the close being forwarded or not, because maybe it's due
to a bug that was fixed since 1.5.3.

Thanks,
Willy




abortonclose for established connections?

2015-04-17 Thread Ludovico Cavedon
Hi,

I am trying to find a solution to the following issue.

I have a client A that sends hundreds of HTTP requests per second to
server B running ha-proxy 1.5.3.
Server B/haproxy forwards them to server C.

Some of these request are long-polling: server C will receive the
request and hang for a very long time (even hours potentially).
Client A may decide to give up on long-polling request, close the
connection and forget about it.
However, haproxy will keep the connection state half-open, assuming
the client is still there waiting for data.

On client A the connection state will go to FIN_WAIT2, and will be
forgotten after 60 seconds.

After a while, client A will happen reuse the source port for a new
connection, and send a SYN packet. On server B, however, the
connection is still there in CLOSE_WAIT.

I am trying to find a way to avoid this from happening. Ideally I
would like haproxy to close the connection completely if the client
closes its side.
"abortonclose" seemed the right option, but it looks like it works
only if the FIN arrives before the connection to server C has not been
established yet.

The statement from [1] sounded promising:
> In 1.5 we have even improved that a bit further for users of long-polling
> requests. When "option abortonclose" is set, if the client closes the send
> side, then haproxy forwards this closing event to the server.

however it does not seem to happen in my case.

What am I doing wrong? Does it have to do with the fact that
connection to server C are reused/persistent?
Is there maybe a way to tell haproxy to close the client connection if
there is no keepalive?

Thank you in advance for your help!
Ludovico

Here is my haproxy configuration:
global
log /dev/loglocal2
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon

defaults
log global
modehttp
option  httplog
option  dontlognull
timeout connect 5s
timeout client  700s
timeout client-fin 30s
timeout server  700s
timeout tunnel 72h

listen http-internal
bind 10.A.B.C:80
mode http
cookie SERVERID insert nocache indirect
option http-keep-alive
option forwardfor
option redispatch
option abortonclose
capture request header X-Real-IP len 50
default_backend user


backend user
balance hdr(User-Agent)
hash-type consistent
mode http
server serverC01 10.A.B.X:80 check
server serverC01 10.A.B.Y:80 check


[1] http://permalink.gmane.org/gmane.comp.web.haproxy/3862