tavis nörttimaailmassa

EksisONE - artikkeleita ja ohjeita nörttimaailmasta

Nopean WordPressin asennus virtuaaliserverille

Cachet

Katsotaan ensin mikä on lähtötilanne. Kyseessä on 5 USD kuussa maksana 1G/1CPU dropletti, joka on asennettu näiden ohjeiden mukaan. WordPressissä ei ole muuta sisältöä kuin Hello World postaus (jonka kautta mittaus tehtiin), eli sekin on täysin muokkaamaton. Kävijöiden määrää nostettiin tasaisesti minuutin aikana 250 samanaikaiseen kävijään.

 

Kuten näkyy, niin serveri hidastui samaan tahtiin kävijämäärän kasvun kanssa. Kun sivustolla oli 50 yhtäaikaista kävijää katsomassa yhtä sivua, niin latausajat olivat lähes 2,5 sekuntia. Tuo on vielä siedettävää. Mutta 100 yhtäaikaisella oltiinkin jo lähemäpänä 5 sekuntia, ja se alkaa olla hidasta. Google alkaa hermostumaan 7 sekunnin jälkeen ja se saavutettiin noin 180 samanaikaisella. Hakutuloksista alkaisi tippua, kun ylitetään 12 sekuntia. Testi onneksi loppui, kun 250 samanaikaista oli paikalla ja siinä vaiheessa latausajat olivat 10 sekunnin luokkaa.

Jotain on siis tehtävä. Ensimmäinen asia on tietysti ostaa isompi droplet, eli enemmän muistia ja useampi prosessori. Mutta se on kilpavarustelussa tuppaa häviämään rahat ja silti ei ole koskaan ensimmäisenä maalissa. Joten otetaan käyttöön välimuistit, cachet.

Redis

Redis on objektivälimuisti. Tuo termihirviö tarkoittaa yksinkertaistettuna, että Redis välimuistittaa esimerkiksi PHP-kutsuja, joita tehdään tietokannalle, kun sivua rakennetaan. Jos Googletat WordPress + Redis, niin löydät melkoisia hehkutuksia miten sivustot ovat nopeutuneet tuhasia prosentteja. En tiedä miten he ovat sen mitanneet, sillä Redis ei nopeuta sivustoja. Redis vähentää teeman ja lisäosien vaatimien kutsujen määrää, mutta edelleen joudutaan kuitenkin muodostamaan tietokantayhteys. Jos mietitään perustana olevaa tekniikkaa, niin webserverin ja PHP:n yhteys tietokantaan on merkittävin hidastava kapeikko.

Redis helpottaa kuormaa, jolloin sivusto saattaa pysyä paremmin pystyssä.

Asennetaan se, jo kohtuullisen tutulla tavalla:

apt install redis-server

Siirretään Redisin asetustiedosto turvaan:

mv /etc/redis/redis.conf /etc/redis/redis.conf.backup

Tehdään uusi conf-tiedosto:

nano /etc/redis/redis.conf

Avaa tiedosto ja kopioi sisältö. Siitä ei tarvitse sen enempää muuttaa, mutta jos/kun sinulla on riittävästi muistia (lue: 4 gigaa tai yli), niin etsi kohta maxmemory 64mb ja voit nostaa sen vaikka 128 megaan. Todella kiireisillä ja isoilla servereillä sitä kannattanee nostaa vieläkin enemmän.

Sallitaan Redisin käynnistyminen serverin mukana:

systemctl enable redis-server

Käynnistetään Redis:

systemctl start redis-server

WordPress ei osaa suoraan hyödyntää Redisiä, joten siihen tarvitaan lisäosa. Varmista, että olet edelleen hakemistossa /var/www/eksis.dev.

Asennetaan lisäosa WordPressiin:

wp plugin install redis-cache

Muokataan wp-config.php tiedostoa:

nano wp-config.php

Kopioi tämä alkuun, heti <?php jälkeen seuraavalle riville:

Otetaan lisäosa käyttöön:

wp plugin activate redis-cache

Käynnistetään myös PHP-FPM uudestaan:

systemctl restart php7.4-fpm

Kirjaudu WordPressin hallintaan. Mene kohtaan Apuohjelmat > Redis ja ota Redis käyttöön klikkaamalla sinistä painonappulaa Enable Object Cache.

Nyt sinulla WordPress osaa hyödyntää Redisiä.

Nginx ja sivukohtainen välimuisti

Jos etsit WordPressiin cache-lisäosaa, niin paras on ehdottomasti WP Rocket. Se muodostaa dynaamisesta sisällöstä staattisia valmiita sivuja, jotka sitten tarjoillaan kävijälle. Webhotelliasiakkaille se on ehdoton hankinta ja nopeuttaa sivustoa huomattavasti. Ei tarvita enää tietokantakutsuja ja PHP:tä, koska sivut on tehty valmiiksi odottamaan käyttöä.

Itse käytän sitä myös serveritason cache-ratkaisujen kanssa. Nopeuttaa entisestään.

Virtuaalipalvelimella voidaan mennä astetta pidemmälle, ja ilmaiseksi. Annetaan Nginxin olla ns. reverse proxy. Tuo on suomeksi ehkä käänteinen välimuisti. Proxy suhtautuu eräällä tavalla muuhun maailmaan yhtenä ja tarjoaa kuin yhdelle kävijälle erilaista sisältöä. Reverse proxy tarjoaa samaa välimuistitettua sisältöä usealle eri kävijälle – siksi se on käänteinen.

Suomeksi: Nginx tekee välimuistiin kopion jo käydystä sivusta eikä päästä kävijää webpalvelimelle. Tässä Nginx on hieman jakomielitautinen, koska se itse on niin cache kuin webpalvelinkin – mutta pointti on siinä, että säästetään kaikki se aika, joka sivun tekemiseen menisi.

Ero esimerkiksi WP Rockettiin tulee siinä, että kun kävijä haluaa katsoa jotain sivua, niin webpalvelin kysyy ensin WordPressiltä onko moista, jolloin WP Rocket (ja muut cache-lisäosat) astuu esiin ja sanoo, että hänellä on moinen, koska koko sisältö on rakennettu taustalla staattiseen muotoon. Se sitten siirretään kävijälle.

Kun Nginx on cachenä, niin kävijän halutessa  sivua Nginx ei kysele keneltäkään mitään, vaan antaa sen omasta muististaan. WordPressin näkökulmasta ketään ei ole koskaan käynytkään. Mutta sivu voidaan tarjota cachestä vain, jos joku on jo katsonut sitä. Ensimmäinen hakee aina sivun WordPressistä (jonka takian WP Rocket hieman nopeuttaa, ainakin yhdelle ihmiselle, myös reverse proxyn kanssa).

Vilkaistaan mitä Nginxin proxy tekee dropletille.

Edellisessä testissä käyttäjälle siedettävän latausajan raja oli noin 50 yhtäaikaisessa kävijässä ja silloin puhuttiin 2,5 sekunnista. Testi oli rajattu 250 yhtäaikaiseen minuutin kuluessa, koska noin 300 kohdalla alkoi tulla muistin loppumisen takia niin paljon virheitä yhteyksissä, että moisessa ei ollut mitään järkeä.

Nyt käytössä oli Redis ja Nginxin cache. Laitoin maksimiksi yhtäaikaisten kävijöiden määräksi 1000, joka saavutettiin minuutissa. Ero on huomattava. Ensimmäiset ovat saaneet 0,4 sekuntia, kun cache lämmitettiin. Sen jälkeen pysyttiinkin tasaisesti latausajoissa noin 0,2 sekunnissa aina 500 kävijään asti, jonka jälkeen muistia kului hitusen lisää ja latausajat vakiintuivat noin 0,3 sekuntiin.

Ilman cacheä 50 samanaikaista sai 2,5 sekunnin latausajan ja cachellä 1000 samanaikaista odotteli 0,3 sekuntia. Miten on, asennetaanko cache?

Testi ei tietenkään kuvaa aitoa maailmaa. Tuossa käytettiin vain yhtä sivua, ja reaalimaailmassa saattaakin tulla 50 kävijää yhtä aikaa, joista jokainen lataa eri sivun, eikä cache pääse mukaan. Mutta kävijäpiikkejä se tasaa tehokkasti.

Koska kaikki asennusohjeet, mukaanlukien tämäkin, esittelevät aina ns. blankkoa WordPress-asennusta, jossa ei ole sisältöä, ei lisäosia, ei page builderia, ei mitään, niin laitetaan näkyviin hieman realistisempi testi. Ajoin saman EksisONE sivuston etusivulle. Käytössä on teema Kallyas (mukava, mutta ei kevyt) ja sisältökin kiertää Basepress FAQ-lisäosan kautta. Cache on kylläkin Varnish, ei Nginxin sisäinen, mutta sillä ei ole käytännön merkitystä tässä.

Kun välimuistia ei ollut, niin 25 samanaikaisellä latausaika oli kahdessa sekunnissa. Kun päästiin 125 samanaikaiseen latausajan ollessa yli 8 sekuntia, niin serveri romahti. Siinä meni rasituksen yläraja 8 GB/4 CPU dropletilla, jossa oli testin lisäksi muilla sivustoilla ehkä noin pari sataa aitoa ihmistä.

Laitetaan cache päälle:

Ero on… dramaattinen lienee sopiva kuvaus. Cachen avulla yhden minuutin aikana saapuneen 250 kävijän kanssa latausajat pysyivät alle 0,8 sekunnissa. Ajoin toisen testin, jossa sivustolle ajettiin minuutin aikana 10 000 kävijää. Latausajat menivät yli 2 sekunnin noin 750 kävijällä. Ensimmäiset ongelmat alkoivat tulla noin 4500 kävijän paikkeilla, jolloin tuli ensimmäiset time-ot virheet, latausajat olivat hieman yli 8 sekuntia. 5000 kävijän kohdalla joka viides sai jo time-outin ja noin 5200 samanikaisen kohdalla serveri ei enää kestänyt. Kaatuminen tuli liian monesta auki olevasta yhteydestä ja hoituisi osaksi useammalla prosessorilla, osaksi hieman säätämällä.

Tuo kaikki tarkoittaa muutamaa asiaa:

  • yksikään kuluttajatason webhotelli ei milloinkaan selviä kävijäryntäyksestä ja kuolinpiste tulee aiemmin, jos käytetään mitä trahansa page builderia (tai edes Jetpackiä; älä käytä sitä, koskaan). Minulla raja meni aikoinaan noin 40 yhtäaikaisessa aidossa ihmisessä, kun WordPressissä pyöri samaan aikaan Woocommerce ja verkkokoulutuksia. Ihmiset eivät pidä satunnaisista, vaikkakin lyhytaikaisista, sivusto on saavuttamattomissa -ilmoituksista
  • kuormitusta vastaan voi taistella rahalla, mutta sitä palaa melkoisesti. Cachen kanssa selviää vähemmällä. Itseasiassa aivan jokainen maailman hiukankaan suositusta sivustosta joutuu käyttämään jotain load balancer ratkaisua.
  • mitä suositummaksi saat sivustosi, niin sitä enemmän joudut maksamaan. Hyväksy tämä heti, niin myöhemmin on helpompaa. Yksi syy siihen miksi sinun on pakko saada harrastelijasivustokin tuottamaan edes hiukan. Tai sitten maksat itse harrastuksena sen, että ihmiset saavat kuluttaa sisältöäsi. Tilanne on kuitenkin yksinkertainen: joko annat arvan ratkaista kuka pääsee sisään tai maksat enemmän. Lompakonavaushetkeä pystyy siirtämään cachellä, mutta se tulee taatusti vastaan.

Joten kun tuo kaikki on summattu, niin avataan Nginxin asetukset ja tehdään cache.

nano /etc/nginx/nginx.conf

Etsi alhaalta lohko Cache settings. Poista kommentointi fastcgi_cache_key ja add_header riveistä eli poista risuaita #.

Kohdan pitäisi näyttää tältä:


##
# Cache Settings
##

fastcgi_cache_key "$scheme$request_method$host$request_uri";
add_header Fastcgi-Cache $upstream_cache_status;

Tehdään uusi virtual host:

nano /etc/nginx/sites-available/eksis.dev.cache

Lisää tämä. Muista muuttaa IP-osoitteet sekä eksis.dev.

Nyt löytyy kaksi virtual hostia. Toisessa ei ole cache käytössä ja toisessa on. Nopein tapa ottaa cache pois, tai laittaa se takaisin päälle, muuttaa tiedostonimeä. Toki saman saa tehtyä Nginxin komennoilla, joilla otetaan virtual host pois tai otetaan käyttöön, mutta minusta tämä on nopein tapa. Plus varmistaa, että koskaan ei ole vahingossakaan käytössä samalle virtual hostille kahta konffia.

Helppouden nimissä, jos et vielä ole server-available hakemistossa, niin siirrytään sinne. Silloin ei tarvitse antaa polku tiedostonimen mukana.

cd /etc/nginx/sites-available

Tarkista, että sinulta löytyy nyt kaksi conf-tiedostoa, eksis.dev ja eksis.dev.cache: komento on ls

Nyt halutaan cache päälle. Tehdään se uudelleennimeämällä

  • eksis.dev tiedostoksi eksis.dev.normaali ja
  • eksis.dev.cache nimelle eksis.dev
mv eksis.dev eksis.dev.normaali && mv eksis.dev.cache eksis.dev

Jos jossain vaiheessa haluat ottaa cachen pois päältä, vaikka jonkun ongelman takia, niin tehdään sama toisinpäin.

mv eksis.dev eksis.dev.cache && mv eksis.dev.normaali eksis.dev

Vinkki: Jos et ole vielä tullut ajatelleeksi, niin uudelleennimeämiset onnistuvat FTP-ohjelmalla melkoisen paljon jouhevammin. Ainakin minulla.

Koska aiemmin säädettiin myös nginx.conf tiedostoa, niin nyt Nginx on pakko uudelleenkäynnistää. Mutta varmistetaan ensin, että ei ole kirjoitusvirheitä.

nginx -t
systemctl restart nginx

Mitä tehtiin

fastcgi_cache_path /var/www/eksis.dev/cache levels=1:2 keys_zone=eksis.dev:100m inactive=60m;
  • polku kertoo mihin Nginx kirjoittaa välimuistitetut sivut. Minulla se on eksis.dev hakemistossa samassa tasossa kuin public_html, jolloin se ei sekaannu varsinaisiin sivuston tiedostoihin, mutta on kuitenkin samassa paikassa kuin sivuston muutkin asiat. Toinen tapa olisi tehdä var/www hakemistoon cache-hakemisto, jonka alla olisi erikseen jokaisen serverin sivuston cachet – silloin polku merkittäisiin /var/www/cache/eksis.dev – älä mieti tätä liian kauan, koska nuo ovat muutettavissa myöhemminkin, ja kyseessä on vain sinun tottumuksiisi ja mukavuuteesi liittyvä asia.
  • inactive on aika, jonka jälkeen sivu poistetaan cachestä, jos sitä ei ole kukaan käyttänyt. Taas niitä asioita, joille ei ole oikeaa eikä väärää ratkaisua, vaan se mietitään tilanteiden ja tarpeiden mukaan. Nämä säädöt ovat jatkokurssimateriaalia ja 60 minuuttia on hyvä kesto aloittaa.
eksis.dev.cache
  • WordPressissä on paljon osia, joita ei voida välimuistittaa, koska ne ovat käyttäjäkohtaisia. Sisäänkirjautuneita ei saa välimuistittaa, sama juttu verkkokaupan asiakastilin, ostoskorin tai kassasivun kanssa. Nyt käytössä oleva esimerkki ei ole täydellisen kattava ja saatat joutua lisäämään jotain. Esimerkiksi jos käytät bbPress-foorumia, niin sitä ei kannata välimuistittaa.
  • Kommentoinnit kertovat mihin mikäkin kohta vaikuttaa.
  • Suljettavat urlit ovat aika itseäänselittäviä, kun muistaa, että ne ovat aina urlin osia. Jos osoite sisältää kielletyn merkkijonon, niin sitä ei välimuistiteta. Samankaltaisia osoitteita voidaan laittaa samaan sääntöön, kuten esim. (cart|checkout|my-account). Silloin pystyviiva, jota kutsutaan usein sen muun toiminnan takia pipeksi, on sama kuin tai.
  • Esimerkin säännöt eivät välimuistita etusivua index.php. Ensinnäkin se on usein melkoisen dynaaminen, eli siellä esittellään uusimmat tai suosituimmat postaukset jne. Se on myös useimmiten sivuston turhin ja vähiten käytetty sivu, eikä siihen kannattaisi muutenkaan sen suurempia panostaa – mutta tuo on jo hieman eri asia.
  • Cacheissa määrittellään usein TTL-aika, joka on jotakuinkin sama kuin parasta ennen päiväys eli kuinka kauan sivu tai objekti pidetään välimuistissa, ennen kuin pakotetaan hakemaan tuoreempi. Se on esimerkissä asetettu samaksi kuin nginx.conf tiedoston sääntö, joka määrää kuinka pitkän käyttämättömyysajan jälkeen on haettava tuore versio eli 60 minuttia: fastcgi_cache_valid 60m;. Cachen aikojen säätely on taiteenlajinsa ja selvästi muuttumattomille asioille, kuten vaikka kuville, kannattaa laittaa pitkät ajat luokkaa vuosi. Mutta tuo on jatkokurssiasiaa ja lähde liikkeelle tunnista.

Voit tarkistaa cachen toimivuuden. Koska etusivua ei päästetä välimuistiin, niin kokeillaan Moikka maailma postauksella. Anna komento:

 curl -I https://www.eksis.dev/moikka-maailma/

Jos se ei toimi, vaan pitäisi käyttää artikkelinumeroa malliin ?p=1 niin käy muuttamassa osoiterakenne. Jo siksikin, että Nginx ei laita cacheen osoitteita, joissa on kysymysmerkki mukana.

Ensimmäisellä kerralla saatat saada tällaisen:


HTTP/2 200
server: nginx
date: Sat, 06 Jun 2020 11:18:03 GMT
content-type: text/html; charset=UTF-8
x-pingback: https://www.eksis.dev/xmlrpc.php
link: <https://www.eksis.dev/wp-json/>; rel="https://api.w.org/"
link: <https://www.eksis.dev/?p=1>; rel=shortlink
strict-transport-security: max-age=31536000
fastcgi-cache: MISS

MISS tarkoittaa, että sivua ei haettu cachestä. Aja tiedosto uudestaan ja viimeisen rivin pitäisi muuttua muotoon

fastcgi-cache: HIT

Se tarkoittaa, että sivu haettiin cachestä, kuten kuuluukin.

On kolmaskin ilmoitus: BYPASS. Se tulee silloin kun Nginx tietää, että periaatteessa url olisi haettavissa cachesta, mutta koska olet kirjautuneena (jolloin cachea ei käytetä), niin tehdään välimuistin ohitus ja haetaan serveriltä aito ja oikea.

Cachen tyhjennys

Cache joudutaan aika ajoin tyhjentämään kokonaan. Englanniksi termit ovat yleensä flush tai purge.. Joko jotain oleellista muuttuu tai on virhetilanne, kuten väärä uudelleenohjaus on livahtanut välimuistiin. Esimerkin ohjeilla moiset virheet poistuvat itsestään tunnin päästä, mutta aina ei ole aikaa odottaa. Cache voidaan tyhjentää kahdella tavalla:

  • koko cache kertalaakista käsipelillä
  • automaattisesti, kun WordPressissä julkaistaan jotain

Nginxin cachen nollaaminen

Koska cache on hakemisto, niin cache tyhjenee poistamalla hakemisto. Tarkista komento aina kahteen kertaan, koska poisto ei varmistele eikä kysy. Jos unohdat komennosta asteriksin * niin poistat myös koko sivustosi.

rm -rf /var/www/eksis.dev/cache/*

WordPressin uudet postaukset

Kun julkaiset uuden postauksen, niin cache on syytä tyhjentää. Valikot ovat saattaneet muuttua tai jonkun widgetin sisältö. Laitetaan uuden jutun julkaisu tyhjentämään cache automaattisesti. Ja kuten arvata saattaa, niin siihen tarvitaan lisäosa.

Varmista, että olet virtual hostin public_html hakemistossa ja komenna:

wp plugin install nginx-cache

Otetaan lisäosa käyttöön:

wp plugin activate nginx-cache

Kirjaudu WordPressin hallintaan. Mene Työkalut > Nginx cache.

Sinun pitäisi antaa lisäosalle tiedoksi Cache Zone Path. Se on sama kuin minkä laitoit virtual hostin konffissa aivan ensimmäiseksi riviksi ja joka kertoo missä cache on. Jos olet seurannut näitä ohjeita, niin se on /var/www/eksis.dev/cache (ja tietysti omalla domainillasi).

Laita rasti ruutuun Purge Cache ja tallenna.

Nyt aina kun julkaiset jotain uutta, niin Nginxin cache tyhjennetään automaattisesti. Voit tehdä tyhjennyksen myös käsin klikkaamalla punaista nappulaa Purge Cache.

Redis

Redis ei periaatteessa tarvitse cachen tyhjennystä ja cache-aikakin on tyypillisesti lyhyt. Esimerkissä on käytetty 900 sekuntia eli 15 minuuttia ja sekin on osan mielestä turhan pitkä, koska puhutaan PHP:hen liittyvistä asioista. Silti tulee aika ajoin tilanteita, että cache kannattaa tyhjentää.

Aikoinaan Redis aiheutti melkoisestikin ongelmia. Lisäosat eivät muka olleet päivittyneet ja hallinnan valikot palautuivät johonkin vanhempaan muottiin. Tuo kaikki johtui välimuisteista. Nyttemmin tilanne on korjaantunut, mutta silti hyvä taktiikka on tyhjentää aina Redisin välimuistit, kun mitä tahansa WordPressin koodissa muuttuu. Tarkoittaa sitä, että kun teemat, lisäosat tai WordPress päivittyvä, niin lopuksi tyhjennettään Redis.

Redis tyhjenee komentoriviltäkin:

redis-cli flusall

Kun on päivittänyt WordPressin WordPressissä, niin on hieman tylsää siirtyä cachen tyhjentämisen takia shelliin. Cachen saa tyhjennettyä Redisin lisäosastakin Apuohjelmat > Redis, mutta aina helpompaa olisi, kun asiat ovat kädenojennuksen päässä.

Jos sinulla on WordPressin hallinnan yläpalkissa tilaa, niin sinne saa valikkokohdan, joka tyhjentää Redisin cachen. Lisää tämä Snippets -lisäosaa (tai lapsiteeman functions.php tiedostoon, mutta se on aina huono idea).

Lisää tämä:

Nyt sinulla on helpoiten asennettavat cachet nopeuttamassa ja tehostamassa WordPressin (ja serverin) toimintaa. Loppu on muiden perusasioiden asentamista.