Skip to content

VIP6: What does pipe mean in Varnish5?

Poul-Henning Kamp edited this page Apr 6, 2016 · 3 revisions

Synopsis

The fact that HTTP/2 is multistreamed means we have to decide what "pipe" means going forward

Why?

In HTTP/1 all transactions are serialized and we can therefore decide, on any transaction, to start piping to a backend.

In HTTP/2 transactions happen in parallel and share not only the TCP connection, but also the HPACK compression state.

Piping was originally intended to cater for traffic Varnish did not understand, such as TN3270 with a HTTP lead-in and simular hacks. With HTTP/2 being used as transport protocol for things like websockets, similar considerations apply.

In HTTP/2 we can imagine two levels of piping, either we pipe the full connection, or we pipe stream by stream.

Piping stream by stream is hard, the streams would have to be decompressed and recompressed. We can do that for HTTP, because we know the semantics, but if another carried protocol, such as websockets, decides to implement their own shared-state compression, we'll need to know about that before we can pipe those streams.

At present we have no documented need to pipe stream-by-stream, so Gettys rule " The only thing worse than generalizing from one example is generalizing from no examples at all." controls.

Connection based piping is much simpler, but the decision criteria needs to be thought about.

In HTTP/1 we can stare at a request in vcl_recv{} and make up our mind, we can even modify it, before we send it to the backend.

In HTTP/2 we could stare at the very first request on the connection before deciding, but to maintain HPACK compression-state we cannot modify it.

If the HTTP/2 is being used for another protocol, there will be no request to stare at, and we will only have the IP#'s and possibly the identity of the protocol opening the first stream. (The same could in principle be said for HTTP/1, but we never supported a H/1 connection that didn't at the very least start out as a HTTP request.)

The need for piping in HTTP/1 is a lot smaller than it used to be, and hopefully in V5 it will never be a good idea to pipe a HTTP transaction, unless there is something truly special (read: Non-compliant) about it.

If we pipe per connection only, we can make it an option to send a PROXY header to the backend.

We have still to decide what "piping" means if the backend is a VMOD.

Error handling if piping is attempted illegal times/places needs to be thought about.

How?

1: Drop pipe entirely

After 10 years, it is not unreasonable to take the attitude that Varnish should be able to cope with any HTTP traffic without resorting to piping, and thus we could simply drop it from the feature-set.

As tempting as this might be, pipe has traditionally good escape-mechanism when things got ugly, and loosing that would be step backwards in terms of "tools not policies".

2: Pipe as in "bent pipe"

We introduce a vcl_sess{} which has access only to the connection parameters, the four IPs, any SSL/ALPN or other hints from the transport, and we can decide to pipe that to some ip+port via a backend. Varnish never inspects any of the payload bytes.

The architectural purity of this is appealing, and it does preserve the escape-mechanism as far as it can be determined from the IPs that it is necessary.

3: As much pipe as possible

We introduce req.pipe which can take the values '0' - cannot be piped, '1' can be piped and req can be modified or '2' can be piped but modifications to req will be lost.

For HTTP/1 it will always be set to "1", indicating that piping is possible.

For HTTP/2 it will be set to '2' only for the very first request, and no other requests will be allowed into vcl_recv{} from that connection, until the first request has determined if piping will happen.

If piping is attempted at an illegal time, we fail the session with appropriate noise in VSL.

We add a backend property ".proxy_header" which can be set to '1' or '2' and all connections to that backend gets a PROXY protocol header, and cannot be reused.

Clone this wiki locally