Skip to content

Commit

Permalink
wsgi: Disable Nagle algorithm on client side
Browse files Browse the repository at this point in the history
When sending a PUT request, the http header may be sent in the first
packet when calling con.endheaders(). When we send the first chunk, the
kernel may delay the send because the header packet was not acked yet.

We have seen PUT requests delayed by 40 milliseconds on the server side.
Typically the server receive the header, and then wait about 40
milliseconds for the message body. The actual work for such request may
take less then a millisecond.

This issue was fixed in python 3.5 by using the TCP_NO_DELAY option
after connecting[1]. I backported this change from python 3.5.

Here is example upload before this change:

$ time ./upload RHEL7_1-001.raw https://host:54322/images/test

real    3m42.144s
user    0m16.240s
sys     0m5.515s

OPTIONS /images/test: [200] 74 [request=0.000859]
PUT /images/test: [200] 0 [request=0.040728, operation=0.039781, read=0.038662, write=0.000838]
PATCH /images/test: [200] 0 [request=0.003775, operation=0.003051, write=0.002775]

The server wait 38 milliseconds for a tiny payload written in 838
microseconds.

Here is the same upload after this change:

$ time ./upload RHEL7_1-001.raw https://host:54322/images/test

real	1m2.492s
user	0m16.232s
sys	0m5.619s

OPTIONS /images/test: [200] 74 [request=0.000972]
PUT /images/test: [200] 0 [request=0.002804, operation=0.001437, read=0.000149, write=0.000841]
PATCH /images/test: [200] 0 [request=0.003511, operation=0.002860, write=0.002646]

Now the server read the payload in 149 microseconds instead of 38
milliseconds, and the entire request was completed in 2.8 milliseconds
instead of 40 milliseconds.

[1] https://bugs.python.org/issue23302

Change-Id: Iebbbceafa0aff5c363e281758daace551f8da8f6
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
  • Loading branch information
nirs committed Jun 24, 2018
1 parent af242a2 commit 2e1359a
Showing 1 changed file with 16 additions and 2 deletions.
18 changes: 16 additions & 2 deletions examples/upload
Expand Up @@ -69,6 +69,20 @@ can_zero = False
can_flush = False


class HTTPSConnection(httplib.HTTPSConnection):

def connect(self):
"""
Using TCP_NO_DELAY avoids delays when sending small payload, such as
ovirt PATCH requests.
This issue was fixed in python 3.5, see:
https://bugs.python.org/issue23302
"""
httplib.HTTPSConnection.connect(self)
self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)


def upload_sparse(con, src):
"""
Upload a possibly sparse file by sending the data portions using PUT
Expand Down Expand Up @@ -218,7 +232,7 @@ context = ssl.create_default_context(
purpose=ssl.Purpose.SERVER_AUTH, cafile=CERTFILE)

# Check the server capabilities for this image.
con = httplib.HTTPSConnection(url.netloc, context=context)
con = HTTPSConnection(url.netloc, context=context)
with closing(con):
server_options = options(con, url.path)
can_flush = "flush" in server_options["features"]
Expand All @@ -229,7 +243,7 @@ with closing(con):
if "unix_socket" in server_options:
con = uhttp.UnixHTTPConnection(server_options["unix_socket"])
else:
con = httplib.HTTPSConnection(url.netloc, context=context)
con = HTTPSConnection(url.netloc, context=context)

# Upload the data. If the server supports "zero", we can upload sparse
# files more efficiently.
Expand Down

0 comments on commit 2e1359a

Please sign in to comment.