OPTIM: http: don't stop polling for read on the client side after a request

We used to unconditionally disable client-side polling after the client
has posted its request. The goal was to avoid subscribing the file
descriptor to the poller for nothing.

This is perfect for the HTTP close mode where we know we won't have to
read on the client side anymore. However, when keep-alive is maintained
with the client, this makes the situation worse. Indeed, after the first
response, we'll have to wait for the client to send a next request and
since this is never immediate, we'll certainly poll. So what happens is
that polling is enabled after a response and disabled after a request,
so the polling is constantly alternating, which is very expensive with
epoll_ctl().

The solution implemented in this patch consists in only disabling the
polling if the client-side is not in keep-alive mode. That way we have
the best of both worlds. In close, we really close, and in keep-alive,
we poll only once.

The performance gained by this change is important, with haproxy jumping
from 158kreq/s to 184kreq/s (+16%) in HTTP keep-alive mode on a machine
which at best does 222k/s in raw TCP mode.

With this patch and the previous one, a keep-alive run with a fast
enough server (or enough concurrent connections to cover the connect
time) does no epoll_ctl() anymore during a run of ab -k. The net
measured gain is 19%.
This commit is contained in:
Willy Tarreau 2013-12-27 23:03:08 +01:00
parent 1208266356
commit 3988d9342f

View File

@ -4473,8 +4473,15 @@ int http_sync_req_state(struct session *s)
* this CRLF must be read so that it does not remain in the kernel
* buffers, otherwise a close could cause an RST on some systems
* (eg: Linux).
* Note that if we're using keep-alive on the client side, we'd
* rather poll now and keep the polling enabled for the whole
* session's life than enabling/disabling it between each
* response and next request.
*/
if (!(s->be->options & PR_O_ABRT_CLOSE) && txn->meth != HTTP_METH_POST)
if (((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_SCL) &&
((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_KAL) &&
!(s->be->options & PR_O_ABRT_CLOSE) &&
txn->meth != HTTP_METH_POST)
channel_dont_read(chn);
/* if the server closes the connection, we want to immediately react
@ -4566,7 +4573,10 @@ int http_sync_req_state(struct session *s)
if (txn->req.msg_state == HTTP_MSG_CLOSED) {
http_msg_closed:
if (!(s->be->options & PR_O_ABRT_CLOSE))
/* see above in MSG_DONE why we only do this in these states */
if (((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_SCL) &&
((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_KAL) &&
!(s->be->options & PR_O_ABRT_CLOSE))
channel_dont_read(chn);
goto wait_other_side;
}