Cookies op Tweakers

Tweakers maakt gebruik van cookies, onder andere om de website te analyseren, het gebruiksgemak te vergroten en advertenties te tonen. Door gebruik te maken van deze website, of door op 'Ga verder' te klikken, geef je toestemming voor het gebruik van cookies. Je kunt ook een cookievrije versie van de website bezoeken met minder functionaliteit. Wil je meer informatie over cookies en hoe ze worden gebruikt, bekijk dan ons cookiebeleid.

Meer informatie

Door , , reacties: 127, views: 138.991 •

Hoe werkt die engine dan?

Zonder dat je weet wat het doel van de engine is, is het uiteraard niet mogelijk om alternatieven te bespreken. Het beschrijven van alle details, performancetrucjes en algoritmes zou dit artikel veel te lang maken, maar hier volgt een samenvatting.

Doel van onze engine

In de praktijk ondersteunt de engine veel van de pagina's in Tweakers 7. Zo wordt de categorieboom die je op de portal van de Pricewatch ziet staan op veel pagina's intern gebruikt. Het gaat dus niet alleen om gegevens die uiteindelijk voor gebruikers zichtbaar worden. In algemene zin geldt dat de engine vooral gebruikt wordt voor het teruggeven van 'item'-lijstjes volgens specifieke criteria, sortering en paginering. Items zijn in deze context bijvoorbeeld onze nieuwsartikelen, reviews, producten of merken. Daarnaast kan de engine informatie afleiden van de in ram opgeslagen items, en daar nieuwe lijstjes en samenvattingen van teruggeven.

Zo'n lijstje kan ook slechts één item bevatten, zodat het gebruikt kan worden voor een detailpagina van een artikel, bijvoorbeeld de pagina die je nu leest. Een lijstje items is echter vaker een zoekopdracht die al dan niet binnen een specifieke context moet plaatsvinden. Denk aan een zoekopdracht voor alle V&A-advertenties met de tekst 'Asus' in de tabletcategorie, waarbij de vraagprijs lager dan 400 euro is. Andere voorbeelden zijn op veel plaatsen te vinden, zoals de nieuwsberichten, reviews, V&A-advertenties en producten. Ook de lijstjes producten en gerelateerde artikelen naast een nieuwsbericht zijn voorbeelden.

Veel pagina's worden opgebouwd uit verschillende engine calls, per lijstje een. Op het moment van schrijven werden er op de reviewportal 11 engine calls gedaan, op de V&A-portal 5 en op de hierboven gelinkte productentab 2. Ook op de pagina die je nu voor je ziet, werden diverse calls gedaan. Onder andere voor het ophalen van het artikel zelf, de categorieboom, de gerelateerde onderwerpen en de gerelateerde artikelen.

In de afbeelding hieronder zie je waar de engine calls op de reviewportal worden gedaan. Iedere aanroep levert genoeg informatie op voor de php-code om zich vooral op de weergave te kunnen richten.

Enginecalls voor de review-portal

Naast lijstjes van items worden ook stukken afgeleide informatie verzameld en teruggegeven. De afgeleide informatie is bijvoorbeeld de informatie die nodig is om te bepalen welke categorieën we moeten tonen in een 'categoriekiezer'. Je wilt tenslotte niet dat er in de V&A-categoriekiezer een categorie wordt getoond die geen advertenties bevat. Ook de populaire onderwerpen onder aan de pagina zijn een vorm van die afgeleide informatie.

Opzet van de engine

De engine is effectief een in-memory objectdatabase die specifiek ontwikkeld is om (veel van) de informatie die je op Tweakers tegenkomt te filteren, sorteren en klaarstomen voor presentatie en om facetten van de resultaten te onttrekken. Bij die informatie horen ook de relaties tussen artikelen onderling en met de tweakbase-entiteiten zoals Categorie, Merk, Serie en Tag.

De engine doet al dat werk zo veel mogelijk op een manier die aansluit bij wat de php-code verwacht en hoe de desbetreffende lijstjes werken. Het is overigens niet de bedoeling dat de engine zich bezighoudt met de presentatie van informatie; dat laten we zo veel mogelijk over aan de php-code.

De informatie op Tweakers is in diverse databronnen opgeslagen. De meeste data zit uiteindelijk in MySQL, de informatie van je bezoekerssessie zit in MongoDB en de multimediabestanden staan op de harde schijf. Om die data efficiënt te kunnen gebruiken wordt sommige informatie in Memcached gecached of wordt bij het opslaan gebruikgemaakt van een Message Queue via ActiveMQ.

Tweakers services schema

Daarnaast speelt onze engine uiteraard een belangrijke rol bij het efficiënt ophalen en verwerken van gegevens. Uiteindelijk haalt de engine die gegevens echter weer domweg uit MySQL en bewaart hij een kopie van die data in 'native' Java-objecten in zijn ram-geheugen. De engine draait als een Servlet binnen Tomcat; het toeval wil dat we met de overstap naar Tweakers 7 ook overgingen op Java 7 en Tomcat 7 ;)

De engines houden die data synchroon met wat er in MySQL staat. Dit doen ze zowel door zelf periodiek, bijvoorbeeld elke vijf minuten, de gegevens te verversen én door te 'luisteren' op verschillende JMS-Topics in ActiveMQ. Bij wijzigingen worden daar dan vanuit php berichten naartoe gestuurd, zodat het voor de php-code niet nodig is om te weten hoeveel engines er draaien en of die wel of niet geïnteresseerd zijn in informatie over de specifieke wijziging.

We draaien momenteel namelijk zes instanties, op iedere webserver een, zodat de communicatie daarmee lekker snel verloopt, met het tcp-verkeer over lokale netwerkpoorten. Dat zou zonder die JMS-Topics echter ook betekenen dat de php-code dan naar zes instanties moet verbinden om te melden dat er wat veranderd is. ActiveMQ kan dat een stuk efficiënter en zorgt ervoor dat de php-code kan doorgaan ten behoeve van de bezoeker die op dat moment zit te wachten.

Een pageview komt uiteraard binnen op een van onze loadbalancers. Wordt daarna meestal doorgestuurd naar een Varnish reverse proxy en die stuurt hem dan, als hij niet in zijn eigen cache zit, door naar Apache. De php-code die binnen Apache de request afhandelt, vergaart vervolgens alle benodigde gegevens uit MongoDB, Memcached, MySQL en de engine, en genereert daarmee de html die, via Varnish en de loadbalancer, wordt teruggestuurd naar je browser.

Tweakers NewRelic service map

Sinds de introductie van Tweakers 7 doen we voor alle pageviews samen gemiddeld 4,8 queries per pageview op onze databases (zowel MySQL en MongoDB), 3,8 queries op Memcached en 3,9 engine calls. De meeste van die 4,8 queries gaan naar MongoDB om je sessie-informatie op te halen en bij te werken. Memcached wordt veel gebruikt voor eenvoudige stukjes informatie, zoals het aantal reacties op een artikel, en de engine uiteindelijk voor de belangrijkste stukken informatie op een pagina.

Een engine call is domweg een REST-operatie (nou ja, we doen alleen http get) met diverse parameters om aan te geven op welke manier de gegevens moeten worden opgezocht, gefilterd, gesorteerd en gepagineerd. Om het werk van de engine zo efficiënt mogelijk te doen wordt de lijst met mogelijke artikelen gesorteerd bewaard, vertaald in bitsets en alleen opnieuw gesorteerd als sortering relevant was en/of anders dan de standaardsortering. De engine handelt voor de meeste calls deze stappen af:

  1. vertaal get-parameters in een filtersettings-object;
  2. bepaal basisbitset voor de objecten, bijvoorbeeld een zoekopdracht, alle producten in een categorie of alle objecten uit een lijstje met id's;
  3. pas overige filtering/facetten toe, bijvoorbeeld alleen producten onder de 400 euro en van het merk Scythe;
  4. indien nodig, verzamel beschikbare facetten en aantallen per filter met in achtneming van and- of or-instructie;
  5. sorteer het resultaat voor als niet de standaardsortering gebruikt moet worden;
  6. pagineer het resultaat voor zover nodig;
  7. vertaal Java-objecten in php-serialized of php's igbinary encoding;
  8. verstuur het resultaat naar de php-kant.

De stappen 2, 3 en eventueel 4 zijn dingen die je misschien van Lucene of Solr herkent. De werking is ook vergelijkbaar, met dien verstande dat onze aanpak uiteraard specifiek voor Tweakers is geschreven. Bovendien worden onze objecten niet in 'documenten' vertaald, wat een reeks vertaalslagen tussen allerlei stukken geheugen bespaart.

Doordat de stappen 1 tot en met 6 doorgaans snel klaar zijn, zit in de praktijk de meeste tijd in de stappen 7 en 8. Voor veel requests loopt dat op tot 90% van de tijd. Gelukkig kunnen we die tijden nog steeds in enkele milliseconden uitdrukken, maar het genereren van alle binaire of tekstuele output om de serialized representatie van php-objecten te genereren is helaas niet gratis. De alternatieven zijn echter niet beter; het is in de praktijk veel sneller dan bijvoorbeeld het generen van xml en nauwelijks trager dan er Json of vergelijkbare compacte datarepresentaties van te maken. Bovendien is het aan de php-zijde terugvertalen van xml, Json of andere opties een stuk duurder dan domweg unserialize aan te kunnen roepen. In de praktijk bleek dat we beter een beetje meer werk aan de Java-zijde konden doen dan php opzadelen met een complexe vertaalslag.


Door Arjen van der Meijden

- Lead Developer

In Oktober 2001 begonnen met als voornaamste taak het technisch beheer van het forum. Daarna doorgegroeid tot senior developer en software architect. Nu lead developer, met een leidinggevende taak aan het team van programmeurs en systeembeheerders van Tweakers.net.

Lees meer over



Populair:Apple iPhone 6Samsung Galaxy Note 4Apple iPad Air 2FIFA 15Motorola Nexus 6Call of Duty: Advanced WarfareApple WatchWorld of Warcraft: Warlords of Draenor, PC (Windows)Microsoft Xbox One 500GBSamsung

© 1998 - 2014 Tweakers.net B.V. Tweakers is onderdeel van De Persgroep en partner van Computable, Autotrack en Carsom.nl Hosting door True

Beste nieuwssite en prijsvergelijker van het jaar 2013