2014-05-13 2 views
12

Mit Varnish 4 habe ich eine Reihe von Backends, die mit einem gültigen Content-Length Header und keine Transfer-Encoding Header antworten.Wie kann ich die Codierung "Transfer-Encoding: chunked" in Varnish deaktivieren?

Auf dem ersten Treffer von einem Client, anstatt mit diesen Header an den Client reagiert, Lack sinkt die Content-Length Header und das Hinzufügen von Transfer-Encoding: chunked auf die Antwort. (Interessanterweise scheint die Payload keine Chunks zu enthalten - es ist eine zusammenhängende Payload).

Dies verursacht schwerwiegende Probleme für Clients wie Flash-Videoplayer, die versuchen, Segment-Größe, Bandbreite, usw. Analyse basierend auf der Content-Length-Header zu tun. Ihre Analyse fehlschlägt, und sie können nicht Dinge tun, wie Multi-Bitrate-Streaming etc.

Ich habe versucht, eine Reihe von halb offensichtlichen Dingen wie:

  • beresp.do_stream = true
  • beresp.do_gzip = false
  • unset req.http.Accept-Encoding

Probe Backend Antwort:

HTTP/1.1 200 OK 
Cache-Control: public, max-age=600 
Content-Type: video/mp4 
Date: Tue, 13 May 2014 19:44:35 GMT 
Server: Apache 
Content-Length: 796618 
Connection: keep-alive 

Musterlack Antwort:

HTTP/1.1 200 OK 
Server: Apache 
Cache-Control: public, max-age=600 
Content-Type: video/mp4 
Date: Tue, 13 May 2014 23:10:06 GMT 
X-Varnish: 2 
Age: 0 
Transfer-Encoding: chunked 
Accept-Ranges: bytes 

Folgelasten des Objekts tun einschließlich der Content-Length Header, nur nicht die erste Last in den Cache.

VCL: https://gist.github.com/onethumb/e64a405cc579909cace1

varnishlog Ausgang: https://gist.github.com/onethumb/e66a2bc4727a3a5340b6

Varnish Trac: https://www.varnish-cache.org/trac/ticket/1506

+0

haben das Problem auch, warten auf Update ohne Umgehung der Streamer. –

Antwort

2

So ist die Lösung überhaupt nicht intuitiv, aber Sie müssen esi Verarbeitung ermöglichen:

sub vcl_backend_response { 
     set beresp.do_esi = true; 

     if(beresp.http.Content-Type ~ "video") { 
       set beresp.do_stream = true; 
       set beresp.do_gzip = false; 
       //set resp.http.Content-Length = beresp.http.Content-Length; 
     } 
     if(beresp.http.Edge-Control == "no-store") { 
       set beresp.uncacheable = true; 
       set beresp.ttl = 60s; 
       set beresp.http.Smug-Cacheable = "No"; 
       return(deliver); 
     } 
} 

So entdeckte ich dies durch Durchsuchen the source code.

Insbesondere Varnish tut dies:

if (!req->disable_esi && req->obj->esidata != NULL) { 
    /* In ESI mode, we can't know the aggregate length */ 
    req->res_mode &= ~RES_LEN; 
    req->res_mode |= RES_ESI; 
} 

Der obige Code setzt die res_mode Flagge.

Wenig später:

if (!(req->res_mode & (RES_LEN|RES_CHUNKED|RES_EOF))) { 
    /* We havn't chosen yet, do so */ 
    if (!req->wantbody) { 
     /* Nothing */ 
    } else if (req->http->protover >= 11) { 
     req->res_mode |= RES_CHUNKED; 
    } else { 
     req->res_mode |= RES_EOF; 
     req->doclose = SC_TX_EOF; 
    } 
} 

Dies setzt die res_mode Flag auf RES_CHUNKED wenn das HTTP-Protokoll HTTP/1.1 oder höher ist (was es in Ihrem Beispiel ist) und die res_mode Flag nicht gesetzt. Jetzt noch später:

if (req->res_mode & RES_CHUNKED) 
    http_SetHeader(req->resp, "Transfer-Encoding: chunked"); 

Varnish sendet die chuncked Transfer-Codierung, wenn die RES_CHUNKED Flag gesetzt ist.

Die nur Weise, die ich sehe, um dies effektiv zu deaktivieren, ist durch Aktivieren des ESI-Modus. Es wird auf einige andere Arten deaktiviert, aber diese sind nicht praktisch (z. B. für HTTP HEAD-Anforderungen oder Seiten mit einem 304-Statuscode).

+0

'if (! (Req-> res_mode & (RES_LEN | RES_CHUNKED | RES_EOF)))' prüft ob 'res_mode' Flag entweder' RES_LEN', 'RES_CHUNKED' oder' RES_EOF' gesetzt hat, aber der Code innerhalb 'if (! req-> disable_esi && req-> obj-> esidata! = NULL) 'RES_LEN' nur zurücksetzen und 'RES_ESI' setzen. Und nach [hier] (https://github.com/varnish/Varnish-Cache/blob/2c2eb9bcf45f75676f91eb6de2a4febd680db716/bin/varnishd/cache/cache_http1_deliver.c#L291) wird die 'Content-Length' schließlich entfernt? – okm

+0

Ich glaube nicht, dass das in Varnish 4 nicht mehr funktioniert. –

6

Zur Zeit wird do_stream = false tun, was Sie wollen.

Das Vermeiden von Chunked Encoding für den Fall, dass das Backend unkunked sendet, ist eine mögliche zukünftige Verbesserung von Varnish.

Beispiel:

sub vcl_backend_response { 
     if(beresp.http.Content-Type ~ "video") { 
       set beresp.do_stream = false; 
       set beresp.do_gzip = false; 
       //set resp.http.Content-Length = beresp.http.Content-Length; 
     } 
     if(beresp.http.Edge-Control == "no-store") { 
       set beresp.uncacheable = true; 
       set beresp.ttl = 60s; 
       set beresp.http.Smug-Cacheable = "No"; 
       return(deliver); 
     } 
} 
+0

Gelöschte meine Antwort, Ihre ist besser –

+0

Ich versuchte 'set beresp.do_stream = false' bereits, mit dem gleichen Ergebnis. :( –

+0

Ich sollte jetzt klarstellen, dass ich mehr Tests gemacht habe. 'Beresp.do_stream = false' verbessert die Erfolgsrate, aber es treten immer noch Fehler auf. Ich habe mindestens eine 10% ige Rate dieses Problems sogar mit' do_stream 'set to' false' –

1

aus Lack Upgraded 4,0-5,2 und jetzt diese korrekt auch für die erste Anforderung funktioniert.

Verwandte Themen