tavis nörttimaailmassa

EksisONE - artikkeleita ja ohjeita nörttimaailmasta

Cachen tyhjennys: purge ja ban

Välimuistin tarkoitus on pysyä. Muuttumattomalla sisällöllä mitä kauemmin, niin sitä parempi. Silti sisältö, tai sivuston ulkonäkö, voi muuttua ja cachen tyhjentäminen tulee ajankohtaiseksi. Yksi yleinen syy välimuistin tyhjentämiseen on enemmän tekniseltä tuntuvat ongelmat, kun joku muutos tai päivitys ei tuntuisikaan tulevan käyttöön. Varnishin cache on helppo ja nopea tyhjentää, muuta ei tarvita kuin systemctl restart varnish, niin palvelimella onkin yhtä äkkiä vapaata muistia rutkasti ja jokainen sivu haetaan backendistä cachen sijaan. Varnishin uudelleenkäynnistyksessä on vain yksi mutta. Se jyrää koko cachen. Ongelmaa ei ole, jos takaa löytyy vain yksi sivusto. Jos Varnish välimuistittaakin useampaa, niin muiden domainien osumien poistaminen vain siksi, että se yksi sivusto on muuttunut, on liioittelua. Sama juttu, jos muuttaa CSS:ää. Ei ole mitään mieltä tuhota välimuistista kaikkea vain siksi, että tyylitiedosto on päivittynyt. Ratkaisu löytyy Varnishin kahdesta eri tavasta poistaa asioita cachestä: purge ja ban.

Noissa kahdessa on yksi olennainen käyttöero tai -tarkoitus:

  • purge on tarkoitettu yhden selvästi määrätyn asian poistamiseen kokonaan cachesta
  • ban on tarkoittu regexin ja VCL:n kanssa käytettäväksi, kun poistetaan useampi asia kerralla ja poisto ei tarkoita cachestä hävittämistä, vaan tiedostojen/kohteiden muuttamista vanhentuneiksi

Noiden kahden ero tulee vastaan, toki poistettavien kohteiden määrässä, jos backend kaatuu. Purgen jäljiltä ei ole mitään tarjottavaa kävijälle, vaan saadaan aikaiseksi virheilmoitus, mutta bannin jälkeen voidaan kuitenkin tarjota cachessä oleva, vaikka se onkin merkitty viimeisen käyttöpäivän ylittäneeksi.

On olemassa kolmaskin, jonka saa käyttöön VMOD asennuksella: softpurge. Siinä laitetaan ensin kohteelle TTL-ajaksi 0 ja purge tehdään grace-ajan jälkeen, ei heti.

Cachen tyhjennys

Cachen tyhjennys kuulostaa kivalta, mutta se mitä se tarkoittaa, riippuu. Halutaanko todella tyhjentää koko Varnishin välimuisti, jolloin systemctl restart varnish on ehdottomasti helpoin ja nopein. Vai halutaanko tyhjentää määrätty url ja onko väliä riskeerataanko saavuttamattomuus, jos backend menee nurin ennen kuin asia on taas välimuistissa. Onko tarve tyhjentää määrätty domain. Onko sittenkin halu saada cachesta pois määrätyt muuttuneet tiedostot, kuten vaikka jos logo on muuttunut (joka onkin mielenkiintoinen urakka saada pois käyttäjien selainten välimuistista, jos sille on tyypilliseen tapaan laitettu vuoden TTL). Vai halutaanko cachestä pois vanha versio content-typen mukaan.

Kaikki tehdään hieman eri tavalla. Kunhan muistaa ne kaksi oleellista asiaa:

  • purge selvälle osoitteelle esim. curlin avulla, ja silloin osoite poistetaan kokonaan heti cachesta
  • kaikelle muulle ban varnishadm kautta, ja varsinkin jos käytetään regexiä, ja silloin objekti pysyy cachessa, mutta se merkitään vanhentuneeksi

Purge

Purge annetaan selvälle urlille, kuten vaikka curlin avulla:

curl -X PURGE https://www.eksis.one/ohjeet/tekniikka/varnish/cachen-tyhjennys-purge-ja-ban/

Tuo poistaisi välimuistista tämän artikkelin.

Vaikka purge poistaa tarkan osoitteen niin pitäisi pystyä poistamaan kaikki sivustoon liittyvä antamalla juuriosoite. Epävarmuuskonditionaali on käytössä siksi, että aina tämä ei ole minulla toiminut ja syytä en tiedä:

curl -X PURGE https://www.eksis.one

Ban

Ylipäätään Varnishin kanssa näyttäisi olevan yleisempää käyttää bannia, ei purgea. Johtunee siitä, että purge todellakin poistaa kaiken, eikä sen kanssa voi käyttää muuta kuin suoria osoitteita.

Bannilla sama koko domainin nollaaminen välimuistista onnistuu default.vcl:stä tuttuun tapaan:

varnishadm
ban req.http.host ~ www.eksis.one

joka bannaa kaikki kohteet, joissa löytyy www.eksis.one.

Koko cachen pitäisi mennä banniin käyttämällä req.url vipua ja pistettä:

ban req.url .

CLI:n käyttö varnishadm kautta antaa jonkun reaktion toiminnosta. Tosin kannattaa muistaa, että ilmoitus 200 ei tarkoita, että komento toimi. Se tarkoittaa vain sitä, että käyttäjällä on oikeus tehdä moinen komento, mutta url tai regex voi silti olla väärin. Jos annat totaalisen virheellisen komennon, niin siitä saat virheilmon, vaikka et olisikaan CLI:ssä.

CLI:hin ei ole pakko mennä, vaan tuon voi myös yhdistää:

varnishadm 'ban req.http.host ~ www.eksis.one'

Toki banniakin voi käyttää urlille, jos siltä tuntuu:

ban req.url ~ /foo

Tuo poistaisi Varnishin takana olevista kaikista domaineista juuressa olevan sivun foo

  • www.example.com/foo
  • www.eksis.one/foo
  • jne

Antamalla suoran urlin tai yhdistämällä (omituisesti) siihen hostin, niin sen saisi tarkaksi:

ban req.http.host ~ eksis.one && req.url ~ /foo

poistaisi vain (www.)eksis.one/foo osoitteen.

Ban sallii kaikkien niiden objektien poistamisen cachesta, joita Varnish voi käsitellä ja täysin samoilla määreillä. Ja tämä on minulle se vaikein asia sisäistää, ja kun sisäistäminen on vajaata, niin käyttö hyödyllisesti on hankalaa – itsestäänselvyys toki. Purge on helppo. Se poistaa cachestä aivan kaiken, joka liittyy määrättyyn urliin. Niin webmasteria kuin leikinkin, niin silti olen hieman laajemmilla valtaoikeuksilla varustettu loppukäyttäjä, joka tekee töitä pääosin WordPress- ja Moodle-maailmassa. Minulle siis sivusto on loppujen lopuksi aina nippu urleja. Minun ei tarvitse miettiä asioita objekteina ja pohtia miten itseasiassa kaikki se, mitä sivuksi kutsutaan, muodostuu. Artikkeli on selväkielistä tekstiä, joka kirjoitetaan editorissa ja jossa voi olla myös kuvaa, ääntä tai videota. Julkaisun jälkeen se muuttuu sitten sivuksi, jolla on url. CSS on asia, jota muutetaan myös editorissa ja sekin näkyy sitten sivussa, jolla on url. Kuitenkin nuo (ja kaikki muut) ovat erillisiä objekteja, ja tuota ei oivalla edes silloin, kun laittaa erilaisia TTL-aikoja kuville ja CSS:lle, jolloin yhden sivun tekstiosuus, kuvat ja muotoilu ovat eri aikoja cachessä jopa ilman bannaamisia ja purgaamisia. Koodarille tuo perusasia on varmasti helppo ymmärtää, mutta takaan, että ei suuremmalle osalle muutoin sivustojen kanssa työskentelevistä. Ja silloinkin kun ero tiedetään, niin sitä ei ymmärretä.

Siksi esimerkiksi se, että bannin voi tehdä myös vaikka http:n content-typelle, jää täysin hyödyntämättä:

ban req.http.host ~ example.com && obj.http.content-type ~ text

Default.vcl kuntoon

Kuten aina, niin kaikki asetetaan Varnishin default.vcl tiedostossa, itsestään cache ei tyhjene käytti sitten purgea tai bannia. Niiden asettamiseen on useakin tapa hieman riippuen siitä kuinka laajaa ja vaihtoehtoja tarjoavaa systeemiä rakennetaan.

Esittelen vain itse käyttämäni asetukset. Jos kiinnostaa, niin voit käydä vilkaisemassa koko setuppini Githubissa: https://github.com/eksiscloud/varnish_6.x

Alkuun, ennen ensimmäistä vcl-lohkoa, on määriteltävä kuka saa purge ja ban-kommennot antaa ja määrättely tehdään IP-osoitteilla. Koska molemmat tehdään komentoriviltä, ja yleensä samalla serverillä, niin localhost on riittävä. Joskus sivustolle laitettu lisäosa tai vastaava ns. etänä tyhjentävä voi tarvita palvelimen julkisen tai yksityisen IP-osoitteen.


acl purge {
   "localhost";
   "127.0.0.1";
}

Ensin määritellään varmistetaan, että BAN ja PURGE tulevat sallittujen listalta.

  • BAN asettaa x-url ja x-ban-url headerit, joiden avulla myöhemmin cachessa olevat objektit merkitään vanhentuneiksi
  • PURGE poistaa suoraan cachesta urlin
  • REFRESH, joka on eräällä tavalla bannin laajennos, joka merkitsee heti urlin vanhentuneeksi ja hakee ilman odotuksia uuden version backendistä

Kaikki tässä määritellyt ovat sellaisia, jotka suoritetaan curlilla malliin curl -X <KOMENTO> – muista käyttää isoja kirjaimia. Jos saat vastaukseksi PURGE ja REFRESH komennoilla pyydetyn sivun sisällön ja BAN tarjoaa error 200, niin komennot onnistuivat (ainakin annettuina).


sub vcl_recv {
..

if (req.method == "BAN") {
   if (!client.ip ~ purge) {
      return (synth(405, "Banning not allowed for " + client.ip));
   }
   ban("obj.http.x-url ~ " + req.http.x-ban-url +
      " && obj.http.x-host ~ " + req.http.x-ban-host);
   # tehdään synteettinen ok, niin pyyntö ei lähde backendiin.
   return(synth(200, "Ban added"));
}

if (req.method == "PURGE") {
   if (!client.ip ~ purge) {
      return (synth(405, "Purging not allowed for " + client.ip));
   }
   return (purge);
}

if (req.method == "REFRESH") {
   if (!client.ip ~ purge) {
      return (synth(405, "Refreshing not allowed for " + client.ip));
   }
   set req.method = "GET";
   set req.hash_always_miss = true;
}

..
}

Pyyntö välitetään backendille.


sub vcl_backend_response {
..

# ban & purge
set beresp.http.x-url = bereq.url;
set beresp.http.x-host = bereq.http.host;

..
}

Kun asia on hoidettu, niin x-headerit täytyy vielä poistaa.


sub vcl_deliver {
..

unset resp.http.x-url;
unset resp.http.x-host;

..
}

Purge komentona vaatii oman lohkonsa. Poiston jälkeen Varnish hakee heti GET-komennolla tuoreen version backendistä. Jos et halua uutta versiota tilalle, niin kommentoi se.


sub vcl_purge {

# Only handle actual PURGE HTTP methods, everything else is discarded
if (req.method == "PURGE") {
   # restart request
   set req.http.X-Purge = "Yes";
   # let's get right away fresh stuff
   set req.method = "GET";
return (restart);
}

..
}