"De site of applicatie is traag geworden." Dat is de melding. Wat erop volgt is meestal een reeks aannames: het zal de database wel zijn, of die ene plug-in, of misschien moet er gewoon meer geheugen bij.

Waarom gokken zo vaak misgaat

Op een lokale omgeving is alles snel. Daar staan tweehonderd producten in de database, geen echte bezoekers, en een cache die precies één gebruiker hoeft te bedienen. De bug die op productie de boel plat legt, is daar onzichtbaar.

Wat je op productie ziet: pagina's die soms laden binnen twee seconden, en soms twintig. PHP-processen die vollopen, en een database die het druk heeft. Wat je niet ziet, is welke regel code dat veroorzaakt.

Serverstatistieken vertellen dát het druk is, niet waarom. Een slow-query-log komt dichterbij, maar laat alleen de queries zien, niet de code die ze afvuurt. En als het probleem is dat er tienduizend snelle queries worden gedaan terwijl het er één hoort te zijn, dan staat er geen enkele query in die log: ze zijn immers stuk voor stuk snel.

Wat profiling wél laat zien

Een profiler meet per request wat er gebeurt: welke functies worden aangeroepen, hoe vaak, en hoe lang elke aanroep duurt. Niet als steekproef op een testomgeving, maar op productie, met echte bezoekers en echte data.

Dat levert een boomstructuur op waarin je van boven naar beneden kunt kijken: de pagina deed er acht seconden over, daarvan kostte deze functie zeven seconden, en die functie deed dit aantal databasequeries. Zo kom je in een paar minuten bij de regel die codevertraging veroorzaakt.

De patronen die zo boven water komen zijn opvallend vaak van hetzelfde kaliber:

  • Het N+1-probleem. Code haalt een lijst op, en doet vervolgens per item nóg een query. Beter is om 'JOIN's te gebruiken.
  • Externe API's synchroon aanroepen, zonder tijdslimiet. Een koppeling met een voorraadsysteem die er soms drie seconden over doet, terwijl een pagina wordt geladen. Beter is om aanroepen op de achtergrond te doen.
  • Caching die niet doet wat iedereen denkt. Een cache met een key die per bezoeker verschilt, en dus nooit 'raak' is.

De shop die bij elk product de hele catalogus laadde

Een webshop werd steeds trager, en niemand kon de vinger erop leggen. Het patroon was verwarrend: de homepage was snel, categoriepagina's redelijk, maar een productpagina kon oplopen tot tientallen seconden. Op de acceptatieomgeving, met een fractie van de producten, was niets aan de hand.

Na het profilen was het binnen een paar minuten duidelijk. Bijna alle tijd van de productpagina ging naar het blok met gerelateerde producten.

De oorzaak zat in maatwerkcode. Om gerelateerde producten te bepalen, haalde de code eerst álle producten op, en deed daarna per product nog een query om te kijken of het in dezelfde categorie zat. Met tweehonderd producten in de testomgeving zijn dat tweehonderd queries: vervelend, maar praktisch onzichtbaar. Met tienduizenden producten in de echte catalogus liep dat op tot een aantal waar geen server tegenop kan.

De oplossing was een paar regels: de selectie aan de database overlaten, met een limiet erop. Geen zwaardere server, geen extra caching-laag. Wat dit voorbeeld vooral laat zien: zonder profiling was dit een stuk lastiger te vinden, want elke afzonderlijke query was snel - het waren er gewoon heel veel.

Waarom wij dit met Tideways doen

Wij bouwen veel graag zelf, maar niet alles. Profiling van PHP is een vak apart: je moet meten zonder de site te vertragen, en dat vereist een extensie die 'diep' met PHP verweven is. We komen dan terecht op het terrein van low-level-programming, en dat is -bewust- niet ons expertisegebied. Tideways doet dat al jaren, en doet het goed.

Daarom koppelt Core direct met Tideways: met één druk op de knop stuurt Core allerhande profiling-informatie naar Tideways, zodat jullie direct ontelbaar veel inzichten krijgen in wat projecten eigenlijk doen.

Wat jullie ervoor terugkrijgen is inzicht in de laag waar wij bewust níet aankomen: jullie eigen code. Wij kunnen de server sneller maken, de database afstemmen en caching inrichten, maar een codeprobleem blijft een codeprobleem. Met Tideways kunnen we die samen goed tacklen.