Do's

  1. Laat de frontproxy het grootste gedeelte van de requests afhandelen
  2. Doe iets met caching
  3. Probeer de applicatie/databaseserver zoveel mogelijk te ontzien
  4. Voor grote files zoals video's het download platform gebruiken
  5. Gebruik voor de front-end een performance benchmark-tool
  6. Gebruik optimalisaties voor je CMS

Dont's

  1. Inefficiente databasequeries
  2. Uitgaande calls naar andere websites
  3. de applicatieserver alle inkomende requests af laten handelen.

Voor de liefhebbers hebben wij een wat meer in-depth uitleg over load balancing. Het belangrijkste om te weten dat de loadbalancers ervoor zorgen dat de frontproxies redundant kunnen worden uitgevoerd. Maar eerst nog wat meer uitleg over wat de frontproxies zijn en doen:

(front-)Proxies

Het hosting platform heeft (Apache) front proxies die geoptimaliseerd zijn om veel verbindingen naar de buitenwereld open te hebben staan. Achter deze front proxies bevinden zich de applicatie servers (workers), hier draaien de ruby, php, java, applicaties. De proxies kunnen statische content (plaatjes, css etc.) direct zelf uitserveren; zaken die ze niet zelf af kunnen handelen moeten ze doorzetten naar de workers/applicatieservers. Deze workers zijn geschikt om hun rekenwerk zo snel mogelijk te kunnen doen, maar ze zijn niet ingericht om veel verbindingen tegelijkertijd open te hebben staan. Dit komt doordat een worker over het algemeen veel meer resources nodig heeft per connectie.

Voor een schaalbare website is het essentieel dat er zoveel mogelijk mogelijk werk door de proxies en zo weinig mogelijk werk door de workers gedaan wordt.

Wellicht helpt het onderstaande diagram bij het begrijpen van de verhoudingen van de componenten



Optimale Applicatieserver/worker performance
Als er werk door een worker gedaan moet worden is het belangrijk dat deze dit zo snel mogelijk doet. Want het aantal 'slots' van de workers is maar beperkt; hoe korter een webserver slot in een worker bezet wordt gehouden voor het afhandelen van een request, hoe meer requests een worker per seconde kan afhandelen. Zolang een worker geen externe afhankelijkheden heeft, is de snelheid waarmee deze requests kan afhandelen puur beperkt door de CPU snelheid van het systeem waar de worker op draait. Als een worker request moet doen naar een database of andere website is die 'externe bron' de beperkende factor. Dat betekent dat alle acties waarbij een worker weer zaken aan iemand anders gaat vragen een risico zijn.

Inefficiente Database queries. Stel bijvoorbeeld dat een worker een query naar een database doet. Op zich heel normaal natuurlijk. Maar terwijl de worker op antwoord van de database zit te wachten doet deze worker niets, intussen hout hij slot bezet. Als er nou tegelijkertijd nog een paar requests binnenkomen die lang moeten wachten op een database query zijn op enig moment alle slots bezet en kunnen er geen nieuwe requests meer afgehandeld worden. Dit merk je dat je site voor alle requests (die niet direct door de proxy afgehandeld kunnen wordn) traag wordt. Ook requests die verder niets met een database van doen zouden hebben. Daarom zijn (inefficiente) requests aan een database die lang op zich laten wachten funest voor de performance van de hele site. In klantenstats kun je terugvinden of er 'slow queries' worden gedaan. In de logging vallen deze (draconische) queries terug te vinden onder:

#vanaf upload-(test)sites
/e/db/$databasenaam/OLDlog/$datum/slowqueries.$datum.gz

Uitgaande (http) calls naar andere websites
Erger nog zijn uitgaande calls naar andere websites. Waar databases altijd in hetzelfde cluster draaien en database calls alleen lang gaan duren als de database overbelast is (met inefficiente queries) kunnen uitgaande calls naar andere websites om allerlei andere redenen traag worden. Bovendien heb je er zelf geen invloed meer op. Stel je website doet een uitgaand request naar -zeg- twitter. En twitter is om wat voor reden dan ook traag. Dan wordt opeens ook je eigen website traag. En wederom: als alle serverslots vol zitten, dan worden alle requests traag. Niet alleen de requests die iets richting twitter doen.

Nog erger dan uitgaande calls naar andere websites zijn uitgaande calls naar de eigen website. (dwz een request op site X die vanuit de code een andere request op site X doet om het eerste request te kunnen beantwoorden) In dit geval kan je een deadlock over je site afroepen. Stel er is 1 beschikbaar serverslot. Dat wordt bezet door een request wat een recursief verzoek naar de eigen site doet. Echter, dat recursieve verzoek moet wachten tot er een serverslot vrij komt. Maar dat serverslot komt niet vrij, want de code daarin staat te wachten op een vrijkomend serverslot… Gevolg: deadlock. De site is nu niet alleen stuk, maar gaat zonder ingrijpen van een beheerder ook niet meer op de been komen.

Hoe valt dit nou allemaal te voorkomen?

Site statisch maken

Door zoveel mogelijk werk aan de proxies te laten wordt al een hoop gewonnen. Zorg ervoor dat plaatjes direct door de proxies uitgeserveerd kunnen worden, zonder dat dit door PHP hoeft. Idem voor platte html, stylesheets e.d.

File Caching + herschrijfregels

Een stapje verder in een statische site is ervoor te zorgen dat bij een request dat niet door de proxy afgehandeld kan worden ervoor te zorgen dat het volgende request (op hetzelfde item) wel door de proxy afgehandeld kan worden. Dat werkt als volgt:

  1. er komt een request binnen
  2. de proxy kijkt op het filesysteem of ie het zelf kan afhandelen. Nee. Gaat door naar een worker. (hiervoor zijn wat apache herschrijfregels nodig in de proxy)
  3. de worker handelt het request af
  4. maar tegelijk schrijft de worker op de plek waar de proxy zojuist keek een kopie van de data van het afgehandelde request weg
  5. bij het volgende request (op hetzelfde item) dat binnenkomt ziet de proxy het zojuist weggeschreven bestand staan en kan het direct zelf uitserveren

Het voordeel van deze aanpak is dat de cache bestanden die door de workers worden weggeschreven helemaal onder het beheer van de website staan. De workers kunnen ze ook weer weghalen, wijzigen e.d. Bijvoorbeeld: stel je hebt een nieuws site. De nieuws items worden op deze manier gecached. Nu komt er vanuit het CMS een mutatie op een item (b.v. inhoud aangepast), dan kan het redactie gedeelte van de website ervoor kiezen om meteen een nieuwe kopie van het item weg te schrijven. Op die manier is de nieuwe versie direct beschikbaar voor de proxies, zonder dat de ze op cache timeouts oid hoeven te wachten.

HTTP Caching

Voor PHP websites bieden we default geen HTTP caching aan, maar op verzoek kan het aangezet worden. In dt geval wordt de proxy een caching proxy en kan deze de responses van de workers cachen.

Goed werkende HTTP Caching is mogelijk vanaf apache-2.4, maar het is onze ervaring dat Nginx de caching nog effectiever afhandelt.

  • De regels mbt java hosting en caching zijn hier ook van toepassing

Gebruik voor de front-end een performance benchmark-tool

Op varvy pagespeed is niet alleen een benchmarktool beschikbaar, ook heeft deze site uitleg over alle elementen die invloed hebben op de performance.

http://yellowlab.tools is de meest kritische benchmarktool.

Pagespeed Insights van Google is de minst uitgebreide tool, maar wordt wel veel gebruikt.

Belangrijke kanttekeningen voor deze tools: alleen de frontend performance wordt gemeten; niet de backend. De schaalbaarheid wordt hier niet mee gemeten. Sterker nog er worden aanbevelingen gedaan die de schaalbaarheid verslechteren zoals mod_gzip/compressie.

Gebruik optimalisaties voor je CMS

Bijvoorbeeld:

  • Drupal optimalisatie De snelle hosting bieden wij al en wat men onder een CDN verstaat is vergelijkbaar met onze proxy setup.

Er zijn voor veel populaire CMS'en modules beschikbaar die plaatjes kunnen optimaliseren of resizen, caching kunnen doen en andere optimalisaties.

Memcached

Standaard bieden we memcached aan. Dit is zeer geschikt om zware database queries in te cachen, om zo de load op de database te verminderen en daarmee de workers sneller te maken.