-
Notifications
You must be signed in to change notification settings - Fork 380
VIP 26: limit private prefetch
- Add means to limit the amount of data prefetched for private objects
- Limit the Transient storage in size by default
While HTTP/1 pipe mode uses a fixed buffer to relay the backend response, for private objects via pass/hfm/hfp, all backend response data is prefetched as quickly as possible from the backend.
This requires potentially unbound amounts of storage and may trigger unexpected errors when transient stevedore allocations (malloc()
in most practical cases) fail.
User expectations are that private object require virtually no cache memmory.
Ref: https://github.com/varnishcache/varnish-cache/issues/2964
- Make the Transient Stevedore limited to 100MB by default
- add a parameter
pass_prefetch
with 1MB default - make
pass_prefetch
adjustable from vcl asbereq.pass_prefetch
- add a no-fail mode to stevedore allocations where the requester gets notified (via a CV) by the stevedore as soon as there is memory available again.
- add a counter for "waiting for storage" events
- use the no-fail mode for private objects
A workaround by using pipe method has been discovered, by using the content length header in the backend response. If (in this example) it shows that the response exceeds 30GB then (by chaining through several methods) restart the request and go into pipe mode.
vcl 4.1;
import std;
sub vcl_backend_response {
if (std.integer(beresp.http.content-length, 0) > 32212254720) {
std.log("DEBUG: Fail this error request, as Transient storage might be insufficient.");
set bereq.http.x-error-reason = "oversize";
return (error);
}
}
sub vcl_backend_error {
if (bereq.http.x-error-reason == "oversize") {
set beresp.status = 599;
return (deliver);
}
}
sub vcl_deliver {
if (resp.status == 599) {
std.log("DEBUG: restarting, backend fetch failed due to oversize");
set req.http.x-pipe-request = "1";
return (restart);
}
}
sub vcl_recv {
# If we have a restart from vcl_deliver, then we immediately go into pipe
if (req.http.x-pipe-request && req.restarts > 0) {
return(pipe);
}
}