I'm working with a varnish configuration I didn't write, and this configuration seems to use (pass)
and (pipe)
interchangeably. I'm a little unclear on what, exactly, the difference between these two actions is.
The manual section on (pipe)
is a little cryptic to me
Pipe can be returned from vcl_recv as well. Pipe short circuits the client and the backend connections and Varnish will just sit there and shuffle bytes back and forth. Varnish will not look at the data being send back and forth - so your logs will be incomplete. Beware that with HTTP 1.1 a client can send several requests on the same connection and so you should instruct Varnish to add a "Connection: close" header before actually returning pipe.
I'm not sure what client they're talking about when they say "short circuit", or what short circuit means in this context, or how varnish shuffling bytes back and forth is different from its normal behavior. i.e. this description is probably great for someone who understands varnish's implementation, but it's a little confusing to someone (me) who understands varnish's role as "pull the results for this HTTP request from memory, or pull the results for this HTTP requests from the application".
So, given that context, what exactly is (pipe)
doing that's different from (pass)
?
(specific backend application I'm working with is Magento, a PHP based ecommerce app, if that matters (mod_php
, FastCGI, etc.)
I'm not a Varnish expert by any means, but this has been my experience and my understanding on pipe vs. pass.
With pass varnish acts as a regular HTTP proxy; it reads the request and pushes it onto the backend(Apache/Nginx)
Pipe, on the other hand, turns varnish into TCP proxy, in the context of Magento this comes handy when the backend returns a file as a CSV, pdf or downloadable file. For example:
if ( req.url ~ ".*/orderprint/.*")
{
set req.http.connection = "close";
return(pipe);
}
Without we would constantly see timeouts when serving files or customers trying to download their downloadable products.
Allan basically sums it up pretty well, to be a bit more detailed we can take a look into Varnish and compare both pass() and pipe():
PIPE:
https://github.com/varnish/Varnish-Cache/blob/master/bin/varnishd/cache/cache_req_fsm.c#L552
In cnt_pipe(...) varnish handles the return (pipe); command.
bo = VBO_GetBusyObj(wrk, req);
generates the new bo
(backend-request object) from the current req
request object.
http_PrintfHeader(bo->bereq, "X-Varnish: %u", VXID(req->vsl->wid));
http_SetHeader(bo->bereq, "Connection: close");
VCL_pipe_method(req->vcl, wrk, req, bo, NULL);
at this point Varnish sets the X-Varnish
and the Connection: close
header on the backend request, and calls VCL_pipe_method (which is taken from the VCL file), so, if you want, you can manipulate the backend request afterwards. The Connection: close
does not need to be set explicitly anymore in your VCL.
After some checks Varnish calls VDI_Http1Pipe(req, bo)
(within the if-statement).
VDI_Http1Pipe
calls http1pipe
, which calls V1F_SendReq
to send the requests and handles all the HTTP stuff. V1P_Process
send the data back to the actual client (which is usually the Browser accessing the page).
Back in cnt_pipe
the function return return (REQ_FSM_DONE);
, so the internal state-machine is done and the request handling is done.
Summed up: Beside explicitly closing the connection and setting the X-Varnish header on the backend request Varnish does nothing else.
PASS:
https://github.com/varnish/Varnish-Cache/blob/master/bin/varnishd/cache/cache_req_fsm.c#L518
Now let's take a look into cnt_pass
, which is the function that handles return (pass);
from the VCL:
Instead of directly calling the VDI_Http1Pipe
method Varnish calls VBF_Fetch
, which uses Pool_Task
to queue the task (the task is to fetch the backend response and deliver that to the client).
When that task is done cnt_pipe
cleans up the memory and returns return (REQ_FSM_DONE);
to ensure there is no additional work to be done, that includes calling deliver
in your VCL file and so on.
CONCLUSION:
pipe
does not actually act as a TCP-Pipe as Allan said, but is very similiar. Calling pipe
basically tells Varnish to send the request, deliver the result and then stop caring about anything (including logging etc.). Basically some kind of fire-and-forget.
pass
also sends out the requests and returns the result to the client, but will ensure that logs are written and Varnish is able to handle it's own stuff, also the deliver
function of your VCL is called, which not happens when you use pipe
.
My understanding, is a (pipe) reads the data and writes it straight out, and a (pass) reads the data in, looks at it and writes it back to the client. The latter adding Varnish headers and the like, the former adding/subtracting nothing. So a (pipe) is as if Varnish doesn't exist.
Or put another way: I think I'm aiming for a schrodinger cat comparison. (pipe) just gives you the box. (pass) looks in the box first.
A (pipe) will also mean that anything that was added to the request up to the call to (pipe), say for example in beresp, is discarded.
One could argue that you would want the (pipe) to be as early as possible for performance but I doubt you would find any metrics on it to really support that argument.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With