Re: pipelining initial request series

On Tue, Jul 05, 2011 at 06:39:22PM -0700, Roy T. Fielding wrote:
> > As a tangential issue, I'm curious: what's the rationale for
> > recommending against pipelining the first series of requests on a new
> > connection in the general case?  When I look at it from a performance
> > perspective, optimistically pipelining seems like a quite reasonable
> > tradeoff.  Consider the common case of a client that has just
> > determined it needs to GET several small resources from a site to
> > which it doesn't already have any connection:
> 
> The problem is that if the server does not want to support persistent
> connections, then sending a lot more data than the server is willing
> to consume is likely to result in a TCP RST which may cancel the buffer
> before the client has finished reading the first response.  Apache's
> lingering close is only going to help with that some of the time.

Indeed that's still an issue with most TCP stacks, but even if the server
supports persistent connections, nothing prevents it from closing after
any response. Some servers close after any error for instance, so in the
end, the same risk exists all the time with pipelining.

(...)
> > In a conservative implementation, the client opens the connection,
> > sends the first request, and waits for the response before deciding
> > whether to pipeline the rest.  In the best-case scenario, the total
> > elapsed time is 3xRTT.  In the worst-case scenario, where the server
> > doesn't allow the persistent connection, the total elapsed time is
> > 4xRTT.
> 
> Yes, but the normal request profile is to request one page and then
> parse it for a bunch of embedded requests (images, stylesheets, etc.).
> In other words, when accessing a server for the first time, the client
> is usually going to wait for the first response anyway.  After that
> first time, the client can remember how the server responded and
> make a reasonable estimate of what it can do with pipelining for
> later pages.  Even if the resources are partitioned across multiple
> servers, there is very little gained by pushing multiple requests
> down the pipe right away because the connection is going to be stuck
> on slow start anyway.

At a customer's (3G provider) we wanted to "fill the pipe" as much as
we could in both directions. We always observed significant holes that
were not caused by the slow start because we already had a sufficient
initial CWND. I tried hard to force them to test with pipelining, they
accepted to test. We never gained anything precisely because of this
first non-pipelined request. The most efficient solution always was to
use many hosts for the servers. In practice, browsers establish many
connections to the servers and fetch requests from these connections.
when you have between 2 and 5 objects to fetch over a given connection,
the browser will still fetch the first one alone then up to 4 others.
This long pause between the first one and the subsequent ones really
was hurting performance.

What's sad was that the next hop was a transparent proxy which did
support pipelining and persistent connections. But even when declared
as an explicit proxy, browsers wouldn't let us pipeline from the first
request. I think something is missing there, as there are scenarii
where there's little or no risk to pipeline and browsers should accept
to pipeline first if configured for such (typically with a proxy, or
when config says always to do so).

> > Thus the aggressive implementation performs 1xRTT faster in the best
> > case.  Yes, it wastes upstream bandwidth in the worst case, because it
> > ends up sending all but one of the requests twice.  But for a typical
> > web browser issuing a series of GETs, upstream bandwidth is an
> > abundant resource and network round trips are expensive, so I'd rather
> > spend bandwidth less efficiently in the worst case to save on round
> > trips in the best case.
> 
> Reasonable people will disagree.  Try convincing Jim Gettys that it
> won't have an effect on network buffers. ;-)

I agree with you Roy that I disagree with Brian :-)  Our upstream bandwidth
was limited too and in the end, by opening many connections to workaround
the lack of pipelining, we were saturating it with far too many SYN-SYN/ACK-ACK
and FIN-FIN-ACK sequences.

The result is that we could never find a satisfying setting. We always had
to trade-off between saturating upstream with TCP and leaving huge holes due
to pipelining. I was a bit frustrated, I admit.

Regards,
Willy

Received on Wednesday, 6 July 2011 05:31:26 UTC