Hi all,
as indicated last week, there were a number of bugs with -dev9 which were
quickly detected and fixed (thanks to Cyril BTW). I also noticed that during
the conversion I lost the getsockname/getdstname calls, resulting in ACLs
on dst never matching, and logs possibly being wrong.
So here is 1.5-dev10 with these issues fixed.
While I'm not fond of mixing fixes and new features, here we're still in
dev and I know that some people will like them, so I have continued the
work towards SSL integration with much more minor changes this time.
I had the time to add the "timeout tunnel" setting, which overrides
"timeout client" and "timeout server" when a connection switches to
tunnel mode (CONNECT forwarded to a proxy, or Upgrade returning 101).
This is mainly aimed at WebSocket setups. Right now people are using
either very long timeouts for all the traffic, or two different backends
with different timeouts in each, and none of these options is good since
all of them require a long client timeout.
With "timeout tunnel", you can keep low values for the client and server
timeouts, and have a large one for the tunnel. It will do the right thing
for you.
I also noticed during debugging sessions that the epoll_ctl() syscall was
making fun of me in the speculative poller. Basically, if a send() failed
after a pending connect(), we would then have the following scenario :
connect(fd) = EAGAIN
send(fd) = EAGAIN
epoll_ctl(ADD(fd:OUT))
epoll_wait() = fd:OUT
send(fd) > 0
epoll_ctl(DEL(fd))
recv(fd) = EAGAIN
epoll_ctl(ADD(fd:IN))
recv(fd) > 0
epoll_ctl() is expensive, we should never have the last two in the middle,
at most one. I realized that I poorly sequenced the sepoll loop. It was
calling speculative events, then updating poll lists, then calling
epoll_wait(), then sometimes calling some speculative events again and
adjusting poll lists again. The sequence above is the result of an already
identified sub-optimization that had to be worked around to speed up recv()
after an accept(). And the epoll_ctl(DEL) followed by an ADD are the result
of this loop...
So I reordered the loop to do this instead :
adjust poll events
epoll_wait()
speculative events
The results are a lot better :
connect(fd) = EAGAIN
send(fd) = EAGAIN
epoll_ctl(ADD(fd:OUT))
epoll_wait() = fd:OUT
send(fd) > 0
epoll_ctl(MOD(fd:IN))
recv(fd) > 0
A performance boost of up to 4.5% on connection rate was observed by just
fixing this !
A second improvement concerns the close() : when an HTTP server sends a close,
we have to respond with a close too. Till now it was done after a wake-up of
the main task, so we had :
recv() = 0
mark buffer as SHUTR
wake up the task
detect the close, decide to do so on the write side
re-scan analysers since the SHUTW flag appeared
In fact, this only happens in HTTP but it's the most important use of haproxy
where performance matters. So now there is a flag in the stream interface
which says that the upper layer is not interested in half-closed connections.
That way, when recv() receives zero, it closes the FD itself before waking up
the task. This has boosted connection rates by up to 7.5% !
So this version may bring 10% or more performance gain on workloads that are
composed of many short connections, and should improve configuration for
those with long connections, it should please everyone, that's why I thought
these changes were welcome with the fixes :-)
For those curious about SSL works in progress at Exceliance, last Friday
evening we managed to establish a backend connection between haproxy and
a server with this code and very little changes. The thing starts to become
a reality :-)
Here's the short changelog :
- BUG/MINOR: stats admin: "Unexpected result" was displayed unconditionally
- BUG/MAJOR: acl: http_auth_group() must not accept any user from the
userlist
- CLEANUP: auth: make the code build again with DEBUG_AUTH
- BUG/MEDIUM: config: don't crash at config load time on invalid userlist
names
- REORG: use the name sock_raw instead of stream_sock
- MINOR: stream_interface: add a client target : TARG_TYPE_CLIENT
- BUG/MEDIUM: stream_interface: restore get_src/get_dst
- CLEANUP: sock_raw: remove last references to stream_sock
- CLEANUP: stream_interface: stop exporting socket layer functions
- MINOR: stream_interface: add an init callback to sock_ops
- MEDIUM: stream_interface: derive the socket operations from the target
- MAJOR: fd: remove the need for the socket layer to recheck the connection
- MINOR: session: call the socket layer init function when a session
establishes
- MEDIUM: session: add support for tunnel timeouts
- MINOR: standard: add a new debug macro : fddebug()
- CLEANUP: fd: remove unused cb->b pointers in the struct fdtab
- OPTIM: proto_http: don't enable quick-ack on empty buffers
- OPTIM/MAJOR: ev_sepoll: process spec events after polled events
- OPTIM/MEDIUM: stream_interface: add a new SI_FL_NOHALF flag
And the usual download links:
site index : http://haproxy.1wt.eu/
sources : http://haproxy.1wt.eu/download/1.5/src/devel/
changelog : http://haproxy.1wt.eu/download/1.5/src/CHANGELOG
Cheers,
Willy