Hem / WordPress / Hur man använder Varnish som en kung

Cache för WordPress med Varnish

AKA ”Hur man använder Varnish som en kung”

Angry Creative tillhandahåller sin egen hosting för att se till att vi kan tillhandahålla mest värde och minimera problem i våra projekt och pågående arbete med våra kunder. Denna produkt kallar vi ”Synotio” och är ett enskilt företag. I den här artikeln delar vår infrastrukturexpert Toni Cherfan hur vi konfigurerar Varnish-cache för att fungera med WordPress och WooCommerce.

Varför?

Beräkningskapacitet är och kommer alltid att vara en begränsad resurs. Tillbaka på 1960-talet under NASAs Apollo-program som förde USA till månen, upplevde Apollo Guidance Computer (AGC) två ”programlarm”, nämligen 1201 (Executive Overflow – No core sets) och 1202 (Executive Overflow – No VAC areas). De orsakades av att astronauterna lämnade radarn i SLEW-läge, vilket översvämmade AGC med avbrottssignaler som hindrade den från att utföra alla uppgifter den behövde: den kunde helt enkelt inte bearbeta data den tog emot i en tillräckligt hög hastighet för att hänga med. Du kan läsa mer om det här.

Konsekvensen av begränsad beräkningskapacitet kan tänkas ha en pool av resurser. Den illustreras som ett cirkeldiagram nedan.

⚠️ Dessa cirkeldiagram är helt godtyckliga och representerar ingen riktig data!

Uncached WordPress site - illustrative resource usage
Uncached WordPress site – illustrative resource usage

Som utvecklare är det ditt ansvar att effektivt använda dessa resurser. Varnish finns för att hjälpa dig med denna uppgift.

Hur?

På en ocachad webbplats påverkas cirkeldiagrammet ovan i hög grad av användartrafikmönster, men också av designval. Till exempel, om du bestämmer dig för att ladda hälften av sidan med AJAX, då ser resurspoolen nu ut så här:

Cached WordPress site - illustrative resource usage
Cached WordPress site – illustrative resource usage

Syftet med en HTTP-gränssnittscache är att ladda ner backend genom att visa resultatet från en begäran för flera användare.

Cached WordPress site - illustrative views model
Cachad WordPress-webbplats – modell för illustrativa vyer
  • På den första sidvisningen är cachen i princip osynlig. Den söker upp begäran i cachedatalagret och hittar ingenting. Begäran skickas därför till backend-webbservern men på väg tillbaka till användaren lagras den även i cachedatalagret.
  • Vid efterföljande förfrågningar för samma sida söker cachen upp begäran på exakt samma sätt som förra gången, men den här gången hittar den en post för den begärda sidan. Svaret skickas därför till nästa användare som begär sidan och så vidare.

Detta innebär en betydande besparing i resurser eftersom istället för att behöva analysera serversideskript, göra databasförfrågningar och kompilera sidan som har begärts, servar cachen helt enkelt om den förkompilerade sidan. Det är skillnaden mellan att behöva köra ett program och att bara servera en statisk fil; en enorm minskning av behövda datorresurser.

Men naturligtvis finns det många situationer där det kan vara dåligt att visa exakt samma sida till flera användare. Låt oss titta på det.

Hantering med cookies

Syftet med cookies är att påverka serverns beteende när du skapar svar. När det gäller användarsessioner innehåller cookien en unik identifierare för den inloggade användaren. Det betyder per definition att ett svar som begärts med en cookie inte kan skickas till flera användare eftersom det genererades för en enskild användare. En begäran med en cookie kan därför verka ocachebar.

I den verkliga världen sätter alla möjliga saker cookies. Ett sådant exempel är Google Analytics och annan spårningsprogramvara. Det är därför olämpligt att anta att bara för att en begäran innehåller cookies, så är den också ocachebar. En lösning är att tvinga begäran att vara cachebar genom att ta bort de användarspecifika delarna av begäran, eller i klartext: avaktivera alla cookies. I VCL-koden (Varnish Configuration Language) görs detta med något som:

sub vcl_recv
{
    	unset req.http.Cookie;
}
 
sub vcl_backend_response
{
    	unset beresp.http.Set-Cookie;
}

Så vad är problemet med att tillämpa ovanstående? Webbplatsen skulle inte kunna generera användarspecifikt innehåll! Detta är nästan bra på en CMS-webbplats, med undantaget att du inte skulle kunna använda admin eftersom admin kräver sessioner. På en e-handelssajt blir problemet mycket värre eftersom varukorgen och kassan per definition är användarspecifika. De skulle inte fungera utan cookies. Därför behöver vi en mekanism för att göra undantag från detta. Detta tas upp i VCL-avsnittet nedan.

🚨 Vissa RIKTIGT dåliga cacheimplementeringar ignorerar cookies som finns i begäran och cachelagrar svaret ändå. Resultatet är en total katastrof där admin, kassan och varukorgen kan cachelagras med data från andra användare. 🚨

⚠️ Det finns faktiskt massor av olika sätt att hantera cookies. Till exempel är Varnishs standardimplementering att bara hoppa över cachelagring av förfrågningar med cookies i dem och du kan i teorin skapa ett dynamiskt sätt att hantera sådana förfrågningar genom att ta emot en header från backend som anger om sidan är ocachebar eller inte, starta om begärd pipeline och ange den för aktuellt bearbetade URL-adressen som en träff för passobjekt. Det finns ingen specifik fördel med hur vi gör saker, det är bara ett designbeslut.

Hastighet då?

En bieffekt av att cachelagra HTTP-svar är att det går mycket snabbare att leverera ett renderat svar från minnet än att rendera det svaret från backend. Datorer är väldigt bra på att kopiera data, och i fallet med Varnish behöver vi bara kopiera en minnesplats till ett nätverksuttag så att webbläsaren kan ta emot det. Detta är storleksordningar snabbare än att starta PHP, ladda WP och läsa igenom webbplatskoden. Detta är dock inte vårt huvudmål!

Vårt mål är att frigöra backend-resurser så att de kan användas bättre. Ta vår resurspool igen:

Uncached WordPress site - illustrative resource usage
Ocachad WordPress-webbplats – illustrativ resursanvändning

Vi har redan konstaterat i cookie-avsnittet ovan att administratören och kassan inte går att cacha. Det gör att sidorna är cachebara. Om man antar en hitrate på 90 % på sidorna skulle detta resultera i en ny resurspool enligt följande:

Cached WordPress site - illustrative resource usage showing freed up resources
Cachad WordPress-webbplats – illustrativ resursanvändning som visar frigjorda resurser

Detta är vad vi vill åstadkomma!

Meme graphic with caption 'Look at all the resources we have now'
”Titta på alla resurser vi har nu”

I det här exemplet kan vi nu öka besökskapaciteten med mer än det dubbla och ändå ha mer utrymme över för annat. Varnish har gjort det möjligt för oss att göra mer med mindre.

⚠️ Den här guiden riktar sig mest till utvecklare, inte marknadsföring som sådan! I marknadsföringsvärlden är det mycket lättare att sälja Varnish som något som snabbar upp din sajt snarare än något som ger dig bättre resursutnyttjande. Detta är dock bara en bieffekt om än en värdefull sådan!

Några ord om hashing

Tänk på cachelagret som en tabell med nyckel-värdepar. Förfrågan är nyckeln och värdet är innehållet i svaret. Begäran omfattar vanligtvis saker som:

  • HTTP-schema (är begäran http eller https?)
  • HTTP-metod (en GET begäran skiljer sig från en HEAD begäran, vilket i sin tur skiljer sig från en POST)
  • URL
  • Webbplatsens domännamn

ℹ Den så kallade ”query string” är en del av webbadressen som ser ut enligt följande ?search=socks – det ser ofta ut ungefär så här som en del av en hel URL: www.yoursite.com/?search=socks

Men att lagra all denna information i nyckeln skulle resultera i massor av slöseri med utrymme eftersom bara en URL i sig kan vara upp till 2048 byte lång! Därför skickas data först genom en hashalgoritm som ligger utanför denna sidas räckvidd (du kan läsa om det här) och komprimeras till att ta mycket mindre utrymme. Detta sker i vcl_hash (se nedan) och hash_data()-funktionen som låter oss lägga till mer data till hash-nyckeln.

Varnish logik (VCL)

Varnish Configuration Language (VCL) är ett programmeringsspråk i sig. Syntaxen och funktionerna ligger utanför ramen för detta dokument (du kan läsa mer om dem här), men begreppen nedan bör vara tillräckligt illustrativa för att kunna läsas av de flesta programmerare.

För att förstå hur Varnish gör saker och hur Synotios standard-VCL fungerar, måste vi titta på Varnish-förfrågans pipeline:

Varnish Configuration Language (VCL) logic
Logik för Varnish Configuration Language (VCL)

Det här ser komplicerat ut, men det finns många steg vi inte behöver bry oss om, som bara sker automatiskt. Låt oss börja från toppen:

vcl_recv

Detta steg anropas när begäran har mottagits av Varnish. Det är i detta skede vi bestämmer om begäran ska vara cachebar eller inte.

Synotios standard vcl_recv ser ut som följer:

sub vcl_recv {
	## Handle PURGE requests differently depending if we're purging an exact URL or a regex, set by the varnish-http-purge plugin
	## See the purging section below for more information on this
	if (req.method == "PURGE") {
		if (req.http.X-Purge-Method ~ "(?i)regex") {
			call purge_regex;
		} elsif (req.http.X-Purge-Method ~ "(?i)exact") {
			call purge_exact;
		}
		else {
			call purge_exact;
		}

		return (purge); ## Terminate the request. There is no point in sending it to the backend since it's meant for varnish.
	}

	set req.backend_hint = cms_lb.backend();  ## Set the backend that will receive the request
	set req.http.X-Forwarded-Proto = "https"; ## Force the backend to believe the request was served using HTTPS

	if (req.url ~ "(wp-login|wp-admin|wp-json|preview=true)" ||  ## Uncacheable WordPress URLs
	req.url ~ "(cart|my-account/*|checkout|wc-api/*|addons|logout|lost-password)" || ## Uncacheable WooCommerce URLs
	req.url ~ "(remove_item|removed_item)" || ## Uncacheable WooCommerce URLs
	req.url ~ "\\?add-to-cart=" || ## Uncacheable WooCommerce URLs
	req.url ~ "\\?wc-(api|ajax)=" || ## Uncacheable WooCommerce URLs
	req.http.cookie ~ "(comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in)" || ## Uncacheable WordPress cookies
	req.method == "POST") ## Do NOT cache POST requests
	{
		set req.http.X-Send-To-Backend = 1; ## X-Send-To-Backend is a special variable that will force the request to directly go to the backend
		return(pass); ## Now send off the request and stop processing
	}

	unset req.http.Cookie; ## Unset all cookies, see the "Dealing with cookies" section
}

vcl_hash

Det här steget är för det mesta oanvänt av våra system, men det finns ett fåtal unika fall där det behövs. Föreställ dig att du har en global butik där du behöver tillämpa olika momssatser beroende på var besökaren befinner sig. I det här fallet måste vi lägga till data till hash-nyckeln för att säkerställa att besökarens GeoIP-land beaktas eftersom backend kommer att producera olika svar baserat på det. Till exempel:

sub vcl_hash
{
	hash_data(req.http.X-GeoIP-Location); # We assume here that the visitor location is stored in a header called X-GeoIP-Location
}

Utan detta kommer vyn för den första användaren att cachelagras och skickas ut för alla användare. Detta har potential att cacha fel data om backend skapar olika svar beroende på variabler som Varnish inte tar hänsyn till.

🚨 Det här exemplet är ganska dåligt på grund av cachefragmentering. Det finns 195 olika länder i världen i skrivande stund. Att cachelagra 195 olika versioner av samma URL skulle sannolikt minska din träff-frekvens till nästan ingenting (se TTL-avsnittet för information om träff-frekvenser). I den verkliga världen skulle vi binda listor över länder till momsprocent och hasha dem istället.

vcl_backend_response

Detta steg anropas efter att begäran har skickats till backend och backend har svarat. Händelser som leder till detta är antingen en return(pass); åtgärd i vcl_recv, eller om den begärda posten inte hittades i cachen. Syftet är att ställa in cache-TTL och göra header-bearbetning.

Synotios standard vcl_backend_responseser ut som följer:

sub vcl_backend_response {
	if ( beresp.http.Content-Type ~ "text" )
	{
		set beresp.do_esi = true; ## Do ESI processing on text output. Used for our geoip plugin and a few others.
					  ## See https://varnish-cache.org/docs/6.1/users-guide/esi.html
	}

	if ( bereq.http.X-Send-To-Backend ) { ## Our special variable again. It is here that we stop further processing of the request.
		return (deliver); ## Deliver the response to the user
	}

	unset beresp.http.Cache-Control; ## Remove the Cache-Control header. We control the cache time, not WordPress.
	unset beresp.http.Set-Cookie; ## Remove all cookies. See the "Dealing with cookies" section above
	unset beresp.http.Pragma; ## Yet another cache-control header

	## Set a lower TTL when caching images. HTML costs a lot more processing power than static files.
		if ( beresp.http.Content-Type ~ "image" )
	{
		set beresp.ttl = 1h; ## 1 hour TTL for images
	}
	else {
		set beresp.ttl = 24h; ## 24 hour TTL for everything else
	}
}

vcl_deliver

Detta steg anropas precis innan svaret levereras till webbläsaren. Den används för att utföra efterbehandling efter att vi har ett svar att skicka. Synotios standard vcl_deliver ser ut så här:

sub vcl_deliver {
	if (obj.hits > 0) { ## Add the X-Cache: HIT/MISS/BYPASS header
		set resp.http.X-Cache = "HIT"; ## If we had a HIT
	} else {
		set resp.http.X-Cache = "MISS"; ## If we had a MISS
	}

	if (req.http.X-Send-To-Backend) ## Our special variable. Signifies a hardcoded bypass
	{
		set resp.http.X-Cache = "BYPASS"; ## If we had a BYPASS
	}

	unset resp.http.Via; ## Remove the Via: Varnish header for security reasons. We don't want to expose that we run Varnish.
	unset resp.http.X-Varnish; ## Remove the X-Varnish header for security reasons. This would otherwise expose the Varnish version.
}

Designa för cachning

När du skriver kod måste du tänka på vilken målgrupp ditt HTTP-svar riktar sig till:

  • Är det riktat till en specifik användare? Om så är fallet är det ocachebart.
  • Är det tänkt att det ska visas för flera användare? Om så är fallet är det förmodligen cachebart.
  • Har det några specifika villkor kopplade till sig som ändrar produktionen baserat på dessa villkor? Om så är fallet behöver det förmodligen speciell konfiguration.

En trevlig sak med JavaScript är att det skalas 100% linjärt med antalet användare på webbplatsen. Varje webbläsare lägger till ytterligare lokal beräkningskraft, därför kommer du aldrig att stöta på problem med serverbelastningen om din kod körs i webbläsaren. En bra jämförelse mellan att designa för cachning och att inte göra det är en valutaväxlare:

Fall 1: Webbläsaren skickar en cookie till servern med ett sessions-ID. Valutan lagras i PHP-sessionen och webbplatsen anger olika prissättning beroende på vad som lagras i den sessionen.

Resultat: Detta skulle göra nästan hela webbplatsen ocachebar eftersom alla sidor med priser förväntas få användarspecifik data (sessionskakan).

Fall 2: Webbläsaren skickar en cookie till servern med vald valuta i klartext (SEK/ZAR/USD/EUR/övrigt). Webbplatsen läser cookien och visar olika prissättning beroende på vad som lagras i den valda valutacookien.

Resultat: Detta kräver speciell konfiguration och är svårt att implementera. Istället för att ta bort cookies helt måste vi analysera cookiefältet, sedan ta bort alla cookies i det förutom valutaväxlingscookien i vcl_recv, sedan lägga till innehållet i resultatet i vcl_hash samtidigt som vi ser till att innehållet i denna cookie når backend. Detta är genomförbart men felbenäget. Att felsöka detta scenario kan snabbt bli en mardröm. Utöver det måste backend göra om bearbetningen för varje fall av ett nytt värde för valutaväxlingscookien. Detta lägger till ytterligare serverbelastning eftersom varje sida nu kan renderas på X olika sätt, där X är mängden möjliga valutor.

Fall 3: Servern matar ut en JSON-array med alla priser på sidan i de olika valutorna. Det visade priset väljs i JavaScript baserat på ett värde i lokal lagring (du kan använda cookies för detta, läs dem bara inte från backend). Sidans innehåll förblir detsamma ur ett Varnish-perspektiv men sidan anpassas vid laddning (i JavaScript) för att passa besökaren. En trevlig bieffekt av detta tillvägagångssätt är att byte till en ny valuta inte skulle kräva en omladdning av sidan om den implementeras på rätt sätt. Servern behöver inte heller rendera samma sida många gånger för att mata ut olika valutor, vilket minskar belastningen.

Resultat: Grymt bra!

Felsökning av cookies

Ditt huvudsakliga verktyg för att felsöka förfrågningar som involverar cookies med denna konfiguration är X-Cache-huvudet. Om det inte finns alls verkar webbplatsen för närvarande inte vara cachad med Varnish (konfigurerad enligt beskrivningen i den här artikeln), du kan behöva kontrollera din serverkonfiguration.

Vid felsökning måste du känna till de inblandade webbadresserna och vilken typ av data som ska skickas fram och tillbaka. Ta till exempel en webbplats som alltid avaktiverar cookies.

Under inloggningen skickas en POST till /wp-login.php med användaruppgifterna. Om referenserna är korrekta måste servern svara med en Set-Cookie-huvud som representerar användarens sessions-ID. Om vi avaktiverar alla cookies, skulle Set-Cookie-huvudet tas bort och nästa URL skulle därför inte se några cookies från webbläsaren som backend just skickade.

Varnish cookie troubleshooting for WordPress CMS login
Felsökning av kakor för WordPress admininloggning

Om vi ändrar ovanstående scenario något där vi fortfarande avaktiverar cookies men bara gör det på GET-förfrågningar, får vi ett annat beteende: Efter POST till /wp-login.php, skickar backend framgångsrikt ett Set-Cookie-huvud till webbläsaren. Webbläsaren lagrar kakan och skickar den vid nästa begäran, vilket är en GET. Backend svarar nu med en omdirigering tillbaka till inloggningssidan eftersom även om webbläsaren skickar cookien kommer Varnish att ta bort den innan begäran skickas till backend. Kom ihåg att GET-förfrågningar är som standard cachebara och kan därför inte ha användarspecifik data som cookies om de inte är kodade i vcl_recv som sådana.

Varnish cookie troubleshooting for WordPress CMS login
Felsökning av kakor för WordPress admininloggning

Om vi ändrar ovanstående scenario igen, men den här gången kodar vi in ett undantag för wp-admin i vcl_recv, får vi en fungerande WP Admin. POST till /wp-login.php ställer in en sessionsidentifierare som en cookie. Webbläsaren tar emot sessionsidentifieraren och fortsätter med en GET-begäran till /wp-admin som innehåller cookien. Varnish vet att denna begäran är ocachebar och skickar därför begäran som den är till backend. Backend svarar med WP adminpanelen eftersom sessionsidentifieraren var giltig.

Varnish cookie troubleshooting for WordPress CMS login
Felsökning av kakor för WordPress admininloggning

Vi använder X-Cache-huvudet för att representera de olika scenarierna:

  • Utdata innehåller ett X-Cache: BYPASS huvud: Varnish fastställde, med hjälp av vcl_recv, att begäran var ocachebar och därför borde skickas som den är direkt till backend.
  • Utdatan innehåller ett X-Cache: HIT hvuud: Varnish fastställde, med hjälp av vcl_recv, att begäran var cachebar och letade upp begäran i cachelagret. Resultatet hittades och serverades från cachelagring utan att involvera backend.
  • Utdatan innehåller ett X-Cache: MISS huvud: Varnish fastställde, med hjälp av vcl_recv, att begäran var cachebar och letade upp begäran i cachelagret. Resultatet hittades inte och hämtades från backend och lagrades sedan i cachelagret. Nästa resultat blir HIT.

De flesta fallen med felsökningar du stöter på kommer sannolikt att vara relaterade till ocachebara förfrågningar som behandlas som cachebara när de faktiskt inte är det. Se till att du bestämmer ovanstående information som en del av din felsökningsprocess. Du kan också manuellt ställa in cookies i din webbläsare som tvingar fram en förbikoppling av cacheminnet, till exempel wordpress_logged_in-cookien. Se avsnittet vcl_recv ovan för möjliga cookienamn.

TTL

ℹ En URL som har lagrats i Varnish-cachelagret kallas ett objekt.

Time To Live (TTL)-värdet satt i vcl_backend_response (se VCL-avsnittet ovan) ställer in hur länge objekt kommer att finnas kvar i cachelagringen. Det är möjligt för objekt att ersättas i förtid om de antingen är förbjudna (rensade) eller om det inte finns plats i cachelagringen och nya objekt behöver läggas till. Varnish kommer att prioritera vilka objekt som ska förvaras i lagringen baserat på hur ofta de används. Objekt som efterfrågas oftare kommer att ha högre prioritet att bli kvar i lagringen jämfört med mindre efterfrågade objekt.

När TTL löper ut tas objektet inte omedelbart bort från cachelagringen. Det är snarare markerat som utgånget och kommer att förbli så tills ett nytt objekt kan ersätta det. När ett utgånget objekt nås under uppslagsfasen (se Varnish request pipeline ovan), finns det olika möjliga designmönster som kan tillämpas:

  1. Hämta ett nytt objekt från backend för att ersätta det utgångna objektet. Så här fungerar vår Varnish-implementation för närvarande under normala förhållanden.
  2. Servera det inaktuella (förfallna) objektet men hämta det nya objektet från backend i bakgrunden. Detta gör att Varnish omedelbart kan leverera en förfrågan utan att behöva vänta på backend. Nackdelen med denna metod är uppenbarligen att vi serverar inaktuella föremål. Vi övergår till denna metod om Varnish-hälsokontrollen har markerat backend som nere. Alternativet skulle vara att servera en HTTP 503 istället.

Det är möjligt att tillämpa fall 2 innan TTL har gått ut, till exempel om den återstående TTL för objektet är mindre än 30 minuter. Detta är användbart för att göra det möjligt för Varnish att uppdatera objekt i bakgrunden samtidigt som objektens TTL respekteras, och vi kan övergå till den här metoden i framtiden.

Den (nästan) oändliga TTL’n

Problemet med låga TTL:er är uppenbart: de kräver att vi hämtar objekt från backend oftare, vilket ökar belastningen på backend och minskar effektiviteten i cachen. Denna effektivitet uttrycks som hitrate, vilket är procentandelen av hur många förfrågningar under en given tidsram som har serverats från cachen. En träfffrekvens på 50 % betyder att hälften av förfrågningarna serverades från cachen och den andra hälften riktades till backend.

När du ökar TTL växer dock problemet med att servera inaktuella data. Detta resulterar i frustration för innehållsredigerare eftersom de nu måste vänta på att TTL ska löpa ut innan användarna ser deras innehåll – eller ännu värre, användare ser produkter som i lager när de faktiskt inte är det. Detta resulterar vanligtvis i förfrågningar om att sänka TTL eller bli av med cachen helt. Vi vill inte göra detta.

Tänk om vi kunde ha det bästa av två världar? Synotios standard TTL är 24 timmar, men det finns skäl att ibland öka detta ytterligare. Den är därför, av praktiska skäl, oändlig. Med en så lång TTL är det inte ett alternativ att vänta på att objektet ska förfalla. Därför kräver vi arbete från applikationslagret (WordPress/WooCommerce) för att hantera detta problem.

Rensning

Det finns bara två svåra saker inom datavetenskap: cache-ogiltigförklaring och att namnge saker.

Phil Karlton

Cache-invalidering, eller rensning, är processen som talar om för Varnish när innehållet på en URL har uppdaterats. Detta är syftet med tillägget varnish-http-purge. Genom att automatiskt ogiltigförklara de relevanta webbadresserna uppnår vi två saker:

  1. TTL spelar ingen roll för att se ändringar, eftersom de kommer att visas direkt.
  2. Vi behöver bara rensa delar av cachen, inte hela cachen.

🚨 När användare får alternativet rensar de vanligtvis hela cachelagringen för att vara säker på att deras innehåll har rensats. Åtgärden att rensa hela cachen har drastiska prestandakostnader och kan till och med sluta med att ta ner backend om belastningen är tillräckligt hög eftersom backend kommer att bombarderas med förfrågningar om objekthämtningar när cachedatalagret är tomt. När det gäller stora webbplatser kan det ta dagar eller veckor innan cachelagret fylls igen.

🚨 Om du stöter på inaktuella data på webbplatsen är det frestande att använda knappen ”Rensa” i admin. Vi rekommenderar inte detta, utan se detta som ett problem som bör skickas in som ett supportärende så att man kan felsöka och lösa det.

Hur vi praktiskt går tillväga för att rensa är att skicka en HTTP PURGE-begäran enligt följande:

PURGE /my/example/resource HTTP/1.1
Host: example.com
X-Purge-Method: Exact

Ovanstående begäran kommer att rensa URLen /my/example/resource, och matcha strängen exakt. Värdet på X-Purge-Method kan vara antingen exakt eller regex och är skiftlägesokänsligt. Om detta huvud saknas kommer vcl_recv att falla tillbaka till exakt rensning.

För regex-frågor ser begäran ut så här:

PURGE /my/example/.* HTTP/1.1
Host: example.com
X-Purge-Method: Regex

Ovanstående begäran kommer att rensa alla webbadresser som börjar med /my/example/ från cacheminnet.

Själva rensningslogiken är implementerad i avsnittet vcl_recv ovan, men upprepas nedan för tydlighetens skull med inkluderandet av de anropade subrutinerna:

sub vcl_recv {
	## Handle PURGE requests differently depending if we're purging an exact URL or a regex, set by the varnish-http-purge plugin
	if (req.method == "PURGE") {
		if (req.http.X-Purge-Method ~ "(?i)regex") { ## Check if X-Purge-Method matches "regex", case insensitive
			call purge_regex;
		} elsif (req.http.X-Purge-Method ~ "(?i)exact") { ## Check if X-Purge-Method matches "exact", case insensitive
			call purge_exact;
		}
		else {
			call purge_exact;
		}

		return (purge); ## Terminate the request. There is no point in sending it to the backend since it's meant for varnish.
	}
}

sub purge_regex {
	## Construct a ban (purge) command in this way:
	## ban req.url ~ "/my/example.*" && req.http.host == "example.com"

	ban("req.url ~ " + req.url + " && req.http.host == " + req.http.host);
}

sub purge_exact {
	## Construct a ban (purge) command in this way:
	## ban req.url == "/my/example/resource" && req.http.host == "example.com"

	ban("req.url == " + req.url + " && req.http.host == " + req.http.host);
}

Felsökning av rensning

Om applikationen inte skickar PURGE-förfrågningar till Varnish på alla åtgärder som ändrar data i cachebara webbadresser, kommer dessa objekt inte att uppdateras och kommer att visa inaktuella data tills TTL för de inblandade objekten löper ut. När du felsöker det här problemet finns det två huvuden som hjälper dig:

  • X-Cache: HIT

    För att cachad data ska vara inaktuell måste den per definition ha lagrats i cachen i första hand. Om du får något annat värde men informationen fortfarande är inaktuell är detta ett tecken på ett problem med backend, inte Varnish.
  • Age: <number>

    Age-huvudet anger hur länge (i sekunder) objektet har lagrats. Du bör se detta värdeökning vid efterföljande förfrågningar. Detta tillåter dig också att avgöra hur länge informationen har varit inaktuell.

När du utfärdar en PURGE för en URL – kommer nästa efterföljande begäran om den URL:en att bli en cachemiss, vilket ställer in X-Cache-huvudet till MISS.

På webbplatser med hög trafik finns det en chans att någon har begärt webbadressen mellan det att du rensat den och du kunde uppdatera din webbläsare. I det här fallet kommer ditt svar att vara en cacheträff men rensningen kommer fortfarande att ha utfärdats korrekt. Titta därför på Age-huvud före och efter din rensningsåtgärd (oavsett om den initierades manuellt eller inte): den bör gå från ett högt värde till ett lågt värde vid rensning eftersom objektet har hämtats mer nyligen från backend.

Om värdet på Age-huvudet inte sjunker när en rensningsåtgärd påbörjas, är det ett tecken på att applikationen antingen inte försöker eller misslyckas när den försöker skicka PURGE-förfrågningar till Varnish.

Edge Side Includes (ESI)

ℹ Den officiella Varnish-dokumentationen om ESI finns här. Det starkt rekommenderat att du läser det innan du gör ESI-implementeringar.

Varnish ger möjligheten att inkludera innehållet i andra webbadresser genom att analysera innehållet i svaret om beresp.do_esi = true (se vcl_backend_response i VCL-avsnittet). Ta det här innehållet till exempel:

<html>
    <body>
        <esi:include src="/README.txt" />
    </body>
</html>

Innehållet i /README.txt kommer att inkluderas i brödtextblocket.

ESI kan också ta bort data!

🚨 Även om ESI kan ta bort data, använd det inte för känsliga saker. Varje instans där sidan renderas utan ESI-stöd kommer omedelbart att exponera den.

<html>
    <body>
        <esi:remove>
            This is a secret message that the browser will never see if ESI support is enabled :)
        </esi:remove>

        Hello!
    </body>
</html>

När det har bearbetats av Varnish kommer ovanstående att mata ut:

<html>
    <body>

        Hello!
    </body>
</html>

Du kan också testa om ESI-stöd är tillgängligt eller inte. Detta är användbart för att kontrollera reservbeteende. Låt oss ta detta till exempel:

<html>
    <body>
        <esi:remove>

            <script>
                var is_esi_supported = false;
            </script>

        </esi:remove>

        <!--esi
            <script>
                var is_esi_supported = true;
            </script>
        -->

        <script>
            console.log("Was this page rendered with ESI support? ", is_esi_supported);
        </script>
    </body>
</html>

Om sidan bearbetades av Varnish ESI-motorn kommer den att se ut så här:

<html>
    <body>
        <script>
            var is_esi_supported = true;
        </script>

        <script>
            console.log("Was this page rendered with ESI support? ", is_esi_supported);
        </script>
    </body>
</html>

Om ESI-stöd inte var tillgängligt kommer utgången att vara oförändrad. Webbläsaren kommer att behandla <esi:remove> som ett element som inte stöds och kommer bara att fortsätta bearbeta HTML-koden inuti den. Taggen <!--esi --> kommer att behandlas som en kommentar och därför kommer innehållet i den inte att utvärderas.

Du kan också kapsla innehåll inuti taggen <!--esi -->:

<html>
    <body>
        <!--esi
            <p>Below will do an ESI include:</p>
            <esi:include src="/README.txt" />
        -->

        This is the only text on the page if rendered without ESI support.
    </body>
</html>

Följande tre taggar är tillgängliga:

  1. <esi:remove>innehåll</esi:remove> tar bort innehåll från sidan
  2. <!--esi --> kommer att ta bort de inledande och efterföljande taggarna, t.ex. <!--esi och --> men bearbeta innehållet i dem.
  3. <esi:include src="url" /> inkluderar innehållet i en annan URL

🚨 Varnish utför som standard endast ESI-bearbetning på HTML- eller XML-innehåll (t.ex. sidor). Försök inte att göra det i JS/CSS-filer.

🚨 Varnish kan bara läsa HTTP (icke-SSL) URL:er. Den talar inte HTTPS/SSL. För att kringgå detta, se till att endast använda ESI för att inkludera resurser som använder relativa sökvägar. T.ex:

/README.txt

inte

https://example.com/README.txt

Vad kan du göra med ESI? Här är ett par idéer:

  • Ha olika TTL:er eller cache-nycklar på delar av samma sida
  • Inkludera delar av dynamiskt innehåll. Till exempel, istället för att be backend-enheten om GeoIP-platsen genom en AJAX-förfrågan som inte kan cachelagras, bädda in den med en esi:include. Detta är främst användbart om URL:en i esi:include-taggen är ett syntetiskt svar med speciell logik i vcl_recv för det.
  • Bädda in SVG-innehåll i HTML utan att behöva bearbeta det via PHP
  • Gör partiell cachelagring, eller fragmentcachelagring, för att dela upp en enskild sida i olika cachebara delar
  • Rensa endast delar av en sida utan behovet att rendera om hela igen, till exempel ändra innehållet i ett huvud utan att behöva rensa alla sidor med det huvudet.
  • Ha flera produktsidor där varje produktkort är en ESI-inkludering. Du kan rensa ett enskilda produktkort utan att behöva rensa produktsidorna. Detta skulle också spara dig från att behöva leta upp alla sidor som en produkt hänvisas till när du rensar produkten.

Slutsats

Om du lyckades ta dig igenom allt detta? Ge dig själv en kaka 🍪

Är VCL din grej? Är du sugen på att göra WordPress snabbare än vad som verkar naturligt och korrekt? Varför inte bli en del av vårt team!

Letar du efter en expertpartner för WooCommerce som kan göra din webbplats snabbare? Varnish är bara början på vad vi kan göra – kontakta oss.

Du kanske även är intresserad av dessa artiklar

briqpay-feat

Mattias Tengblad | Reading time 3 min

Briqpay – flexibel betallösning för B2B e-handel

feat-cro

Mattias Tengblad | Reading time 8 minutes

Konverteringsoptimering

Vad är konverteringsoptimering?. Konverteringsoptimering (CRO) är processen att öka andelen konve…

Read more
feat-cro

Mattias Tengblad | Reading time 8 min

Konverteringsoptimering

feat-app

andershermansson | Reading time 12 min

Affärssystem (ERP) för WooCommerce

Prenumerera på vårt nyhetsbrev och få massor med tips, inspiration och insikt om WordPress och WooCommerce och den digitala världen bortom.

Dags att ta nästa steg mot en affärsnyttigare webb?

Kontakta oss så kan vi prata mer om hur vi tillsammans kan ta er verksamhet till nästa nivå

Loading