Optimalisatie van de website-laadtijd

23 juli 2012, 09:09

Case Marketingfacts

Bij het opzetten en onderhouden van een online platform komt veel kijken. Ook veel technische zaken. Hoewel het niet het meest sexy deel is van je platform, heeft het wel degelijk veel invloed op de performance van de site en de ervaring van gebruikers. Op een langzame site zit immers niemand te wachten. In deze blog ga ik in op enkele maatregelen die we recent op Marketingfacts hebben getroffen om de lange laadtijden op te lossen.

Het probleem

Na de lancering van de nieuwe site hebben we enkele dagen, samen met Mangrove en Exonet, gemonitord hoe de site het hield. Zonder redundante oplossing is dat toch spannend, maar het ging boven verwachting. Wel heeft Mangrove tijdelijk volledige pagina's moeten cachen, waarmee wel de werking van enkele dynamische onderdelen werden gedwarsboomd. Bijvoorbeeld de kliktellers, die bij elke view moet worden geüpdatet. Bij de optimalisatie van deze sociale knoppen komt heel wat kijken, zie deze eerdere blog.

Na enkele weken kregen we steeds vaker problemen met de performance. Na wat eenvoudige tweaks ging dat voor korte tijd even goed, maar het probleem bleef terugkomen. Uiteindelijk bleek dat we massaal gespamt werden via een set standaard formulieren van Expression Engine. De site kreeg daarmee elke 10 seconden een nieuwe aanmelding te verduren. In combinatie met het normale bezoek zorgde dit ervoor dat de laadtijden van de site enorm terugliepen.

Om voor awesome laadtijden te zorgen zijn we bij elkaar gaan zitten en hebben we een stappenplan opgezet om tot structurele verbetering te komen. In deze blog wil ik je meenemen in de maatregelen die we samen met Robert Leefmans, Nick Rockx en Amer Grgic van Mangrove en Jesper Weiland van Exonet hebben getroffen.

Database tabel type

Allereerst heeft Mangrove de het tabeltype van de database aangepast. Globaal gesproken zijn er twee soorten: MyISAM en InnoDB. MyISAM is voor MySQL de standaard wijze waarop informatie wordt opgeslagen in de database, en daarom maakt het gros van de sites gebruik van MyISAM. Ook Expression Engine, het CMS waarmee Marketingfacts is gebouwd, maakt gebruik van de standaard storage engine (zoals het officieel heet). In de meeste gevallen MyISAM dus.

Tussen beide type database engines zitten veel kleine technische verschillen. Zo is InnoDB makkelijker te backuppen en beschikte InnoDB tot voorkort niet over full-text search. Details, zo lijkt het, maar hebben mogelijk grote impact. Het belangrijkste verschil is dat MyISAM op tabelniveau versleuteld, en InnoDB op rijniveau. Wat betekent dit nu concreet? Bij het laden van de homepage worden er flink wat verzoeken aan de database gedaan. Artikelen, reacties, maar ook voor elk artikel wordt opgehaald hoeveel kliks en social shares er zijn. Bij elk van zo'n request wordt er een bewerking op 1 (of meerdere) tabellen. Een tabel is in deze zin overigens niet anders dan 'gewone' gegevenstabellen; bv. een klanttabel, ledentabel, reactietabel, etc.

Als zo'n verzoek wordt gedaan in het geval van MyISAM doet het systeem de tabel tijdelijk op slot, zodat er geen conflict kan ontstaan met andere processen. Dit zou bijvoorbeeld voor problemen kunnen zorgen wanneer er, vrijwel tegelijkertijd, bestellingen worden gedaan van eenzelfde account. Als er niet genoeg tegoed op de bijbehorende rekening staat bestaat het risico dat beide transacties worden voltooid. De locking zorgt ervoor dat eerst transactie nummer 1 wordt voltooid, voordat transactie nummer 2 in werking wordt gezet.

Wel zo veilig dus. Maar het kan er voor zorgen dat de snelheid bij druk bezoek behoorlijk wordt verlaagd. Bij InnoDB tabellen worden geen gehele tabellen gelockt (zoals links afgebeeld), maar gebeurt dat per record/row (afbeelding rechts). Dat zorgt ervoor dat wanneer 'John' uit de database wordt opgehaald, tegelijkertijd 'Bob' of 'Steve' kan worden opgehaald zonder dat deze hoeft te wachten tot het ophalen van 'John' voltooid is. Een klein verschil, maar met een site met veel bezoekers, en daarmee veel requests, kan het een enorme snelheidswinst opleveren. Met name wanneer er wat zwaardere processen tussen zitten die lang beslag kunnen doen op een tabel, en zo voor een file kunnen zorgen. Met het risico dat de site er uit klapt tot de file is opgelost.

Caching

Mangrove heeft met diverse manieren van caching geëxperimenteerd. Exonet was fan van MemCache, en dat werd als eerste getest. De integratie met Expression Engine verliep echter niet soepel als we zouden willen. Er traden nogal wat 'vreemde' bij-effecten. Het ging mis bij de dynamische onderdelen, o.a. sessiedata werd meegecached en kwam bij andere bezoekers terecht.

De oplossing waar Mangrove voor heeft gekozen is het cachen van zogeheten partials. Het is vergelijkbaar de caching in Mangrove's eigen pH8.CMS, en betekent in feite niets anders dat dan gepaalde onderdelen of objecten wél, en bepaalde niét worden gecached. Hiervoor moest de site opzet, die Expresion Engine eigen gericht is op het snel parsen, iets aangepast worden. Een aantal voorgeprogrammeerde blokken code die, door parsing, eenvoudiger worden geladen zijn vervangen met de meer standaard includes waarbij je meer cachemogelijkheden hebt. Met deze aanpassing blijft dynamische content bij elk bezoek vers ingeladen, maar worden meer statische elementen langer gecached.

Resultaat

De aanpasingen zorgde ervoor dat de responsetijden flink zijn teruggelopen, zie ook onderstaande tabel:

Dankzij de aanpassingen is de performance nu zeker acceptabel. Mocht de load toch hoog oplopen, dan heeft Mangrove vervolgstappen klaarliggen. Nick Rockx: “Wat we bij groeiend bezoek nog kunnen gaan inzetten is het cachen en uitserveren van statische content vanaf speciaal daarvoor ingerichte servers. Daarnaast zouden we de hosting nog kunnen opschalen naar een redundante opstelling met meerdere database- en webservers.”

Afbeelding: Esparta (cc)

Afbeelding 2: Joisey Showaa (cc)

Danny Oosterveer
Data-gedreven digital marketeer bij Datasexual

Data-gedreven digital marketeer. Resident bij Amdax en Woonduurzaam. Daarnaast vertel ik vaak als spreker over data-gedreven marketing. Auteur van het boek Data-bedreven marketing. Eén van de twee Groene Nerds.

Categorie
Tags

5 Reacties

    nickrockx

    @Michel Bedankt voor je reactie! Zeker constructief!

    Hoewel iedereen perfectie wil nastreven, zijn er natuurlijk meer factoren die meewegen in processen zoals deze. We hebben in overleg een stappenplan gemaakt waarbij aangetekend werd dat wanneer er na een stap voldoende progressie is gemaakt, we de volgende stappen voorlopig in de ijskast zouden zetten. Een stap waaraan we nog niet zijn toegekomen behelst hetgeen je in jouw reactie hebt genoemd. Voornamelijk in de front end is nog een hoop te doen; caching op fileniveau, met expiratie headers, meer geminifiede scripts, image sprites, filesizes minimaliseren voor images, statische content uitserveer-servers etc.

    Zoals Danny aangeeft hebben we voorlopig voldoende progressie geboekt. We vergeten bijna dat we met de oude site op laadtijden van circa 30 seconden zaten. 😉


    23 juli 2012 om 14:06
    Erwin

    Wat ook een aanrader is om diverse web-performance optimalisatietechnieken te testen. Geoptimaliseerde cache headers, downscalen van afbeeldingen, comprimeren van CSS & JS is een goede stap.

    Als je het helemaal goed wil doen dan zorg je er voor dat je weet welke combinatie van technieken het beste werkt, liefst per browser. Chrome & Firefox reageren nl. niet per definitie op dezelfde manier op je optimalisaties.

    Er zijn diverse platformen om deze zaken te optimaliseren. Je kunt denken aan mod_pagespeed van Google, Strangeloop of SiteSpect. De laatste is eigenlijk een AB & MVT testing tool, maar heeft ook de mogelijkheid om een MVT test op te zetten op optimalisaties in plaats van content of layout met de AMPS module. Zo kun je ontdekken welke combinatie het best werkt in de diverse browsers, niet alleen gebaseerd op snelheid maar ook op conversie.


    23 juli 2012 om 20:42
    Tijs

    De winst uit de hier genoemde (micro)optimalisaties zijn verwaarloosbaar vergeleken met de winst die optimalisatie van de frontend zou opleveren. Dit artikel gaat over de zogenaamde optimalisatie van één van de ruim 120 requests die door de pagina worden uitgevoerd. De daadwerkelijke oplossing (‘partials’ ) wordt niet echt toegelicht. De enige geldige reden om de backend- caching te gebuiken voordat je de frontend optimalisaties uitvoert is wanneer de host het niet aan kan.

    Het artikel had veel potentie, maar is uiteindelijk een beetje een non-artikel geworden.

    Een paar tips:

    – gebruik een CDN voor je statische content, mocht dat lastig zijn met EE, overweeg dan een dienst als CloudFlare

    – Voordat je memcached gaat inzetten is het altijd de moeite waard om de gebruikte onderliggende software het cachen uit te laten voeren (php:apc, mysql: query cache) en te kijken of dat al het gewenste resultaat oplevert.


    30 juli 2012 om 08:30
    DannyOosterveer

    Hi Tijs

    Thanks voor je reactie, CDN hebben we ook zeker in overweging genomen, maar met de huidige optimalisatie hebben we voor Marketingfacts al flinke winst geboekt. Optimalisatie van (uitserveren van) statische content is wat arbeidsintensiever dan de stappen die we tot nu toe hebben gemaakt. Perfectie nastreven is natuurlijk het doel, maar helaas geen onbeperkte tijd en onbeperkt budget 😉

    M.b.t. de partials: het zal lang niet altijd dat zijn waarmee flinke winst gehaald wordt, maar dat was wel waar onze grootste bottleneck zat (queue vorming op de database).


    30 juli 2012 om 10:10

Marketingfacts. Elke dag vers. Mis niks!