Cookies op Tweakers

Tweakers is onderdeel van DPG Media en maakt gebruik van cookies, JavaScript en vergelijkbare technologie om je onder andere een optimale gebruikerservaring te bieden. Ook kan Tweakers hierdoor het gedrag van bezoekers vastleggen en analyseren. Door gebruik te maken van deze website, of door op 'Cookies accepteren' te klikken, geef je toestemming voor het gebruik van cookies. Wil je meer informatie over cookies en hoe ze worden gebruikt? Bekijk dan ons cookiebeleid.

Meer informatie

Door Arjen van der Meijden

Lead Developer

Tweakers' serverpark anno 2013

Webservers

Bij een bezoek aan Tweakers komt je browser uiteindelijk bij de loadbalancers terecht. Nadat een van de loadbalancers je netwerkverbinding heeft aangenomen, stuurt hij de gegevens door naar een van de webservers. In zekere zin zijn de webservers daarom de belangrijkste servers die we hebben. Zonder die krijg je niets, terwijl als een database onbereikbaar is, je in ieder geval nog een foutmelding kunt krijgen. We hebben daarom drie webservers in elk van beide datacentra, zes in totaal. Op deze manier kan zelfs bij uitval van een van de twee locaties nog steeds een webserver uitvallen zonder dat we daar noemenswaardig last van hebben. Aangezien het dataverkeer voor onze primaire locatie gratis is, sturen we 95% van het verkeer daarheen. Er gaat nog wel 5% naar de secundaire locatie, zodat alle caches gevuld blijven en we zeker weten dat die webservers ook gewoon goed werken.

Onze webservers zijn traditioneel behoorlijk zwaar uitgerust. In tegenstelling tot veel andere sites hebben we dus niet een heleboel lichte servertjes. Dat doen we omdat we niet alleen schaalbaarheid belangrijk vinden, maar ook willen dat iedere individuele request snel wordt afgehandeld. Bovendien beperken we zo het aantal servers in onze racks en de hoeveelheid beheer die daarmee gemoeid is. De hardware is voor alle zes servers dezelfde en bestaat momenteel uit:

Onderdeel6x webserver
Server IBM x3550 M3
Cpu 2x Intel X5675, 3.06GHz hexacore
Geheugen 24GB 1333MHz
Disk 1x 146GB 10K SAS

We combineren overigens de taken van 'reverse proxy'-, web- en applicatieservers in deze machines. Dit hebben we gedaan om zowel de spof's te beperken als om nog wat snellere communicatie tussen de diverse dicht op elkaar zittende diensten te faciliteren.

Voor de schaling is dat uiteraard zowel een voor- als een nadeel. Enerzijds is het eenvoudig om er een webserver bij te zetten, zodat de capaciteit van ieder onderdeel toeneemt, maar anderzijds is het lastig om alleen een specifieke taak, bijvoorbeeld de proxyservers, meer capaciteit te geven. We houden dit soort dingen in de gaten en zijn er ook niet vies van om waar nodig taken naar losse servers te verhuizen.

Drie van de webservers gebroederlijk bij elkaar

Varnish

De meeste requests komen eerst binnen bij Varnish. Dit is een zeer krachtige en snelle reverse proxy server, die voorkomt dat onze Apaches zich moeten bezighouden met statische content. Denk bij statische content vooral aan plaatjes, JavaScript- en css-bestanden. We maken al een paar jaar gebruik van Varnish, maar met Phoenix hebben we besloten om alle requests via Varnish te laten lopen. De losse Lighttpd voor tweakimg.net is daarmee komen te vervallen. Er zat uiteindelijk geen snelheidsvoordeel in het gebruik van de losse Lighttpd-webserver voor statische content, terwijl het wel extra software was om te beheren.

Iedere Varnish heeft een eigen cache van 5GB, die alleen in ram-geheugen wordt bijgehouden. Ondanks die relatief beperkte cachegrootte, haalt Varnish bij ons een gemiddelde hitrate van ongeveer 97%. Dat betekent dat er van iedere honderd hits op de webserver slechts drie doorgestuurd worden naar Apache. Zo gek is dat natuurlijk niet, want op een pagina van Tweakers staan al gauw meer dan veertig statische elementen. Het zou zonde zijn om dat allemaal door Apache te laten verwerken, terwijl Varnish dat sneller en met veel minder belasting voor de hardware kan.

Apache en PHP

Tweakers is geschreven in PHP. Hoewel we daar elementen van hebben herschreven in Java, komt elke pageview van een bezoeker nog gewoon binnen op PHP. Daarbinnen wordt dan besloten waar de benodigde data vandaan gehaald moet worden. Dat kan onder andere uit MySQL, MongoDB, Memcached, het bestandssysteem en onze Java-back-end zijn. Voor de routing van requests, en om de onderliggende databeheercode en de weergave ervan te scheiden gebruiken we het Symfony Framework.

Doordat Varnish het gros van het webserver-werk op zich neemt, konden we Apache als applicatieserver blijven gebruiken. Er zijn allerlei snellere alternatieven, waaronder Nginx en Lighttpd, maar die zijn doorgaans lastiger te configureren met PHP en vaak minder krachtig of minder flexibel. Bovendien zijn ze vooral sneller voor de requests die bij ons direct door Varnish worden afgehandeld en ze zijn niet (noemenswaardig) sneller dan Varnish. Zodra je alleen nog maar requests doet waarbij PHP actief is, is er nog maar nauwelijks prestatiewinst met de alternatieve webservers te behalen. Het grootste deel van de tijd zit dan toch in zaken waarop de webserversoftware geen invloed heeft, zoals berekeningen in PHP, en queries naar MySQL en andere databronnen.

Engine

Eind 2012 schreven we uitgebreid over onze Java-back-end. Deze noemen we intern, bij gebrek aan een betere naam, simpelweg Engine. Samenvattend komt het erop neer dat MySQL en PHP samen niet goed overweg konden met de complexiteit van onze Pricewatch of de gecombineerde zoekresultaten die met Tweakers 7 geïntroduceerd werden. En omdat we de filtering van specificaties en dergelijke compleet en snel wilden houden, hebben we uiteindelijk alles herschreven in Java.

Om de communicatie met deze Engines zo snel mogelijk te houden en om ook hier geen spof te introduceren hebben we ervoor gekozen om op iedere webserver zo'n Engine te deployen. Ondanks snelle 1Gbit-switches en -nics is het nog altijd veel sneller om met localhost te communiceren dan over het netwerk te gaan.

De omgeving is opgezet als Java Servlet en we hebben daarvoor op iedere webserver een instantie van Tomcat 7 draaien. Deze heeft 8GB ram toegekend gekregen. Voor de liefhebbers: we gebruiken deze Garbage Collection-parameters:

TypeInstellingen
Geheugen -Xms8G -Xmx8G -XX:+UseNUMA
Permgen -XX:PermSize=256M -XX:MaxPermSize=256M
Garbage Collection -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseCMSInitiatingOccupancyOnly -XX:+CMSClassUnloadingEnabled

Met de standaard-garbage-collector, de Parallel Garbage Collector, bleek dat er zo nu en dan een relatief lange application pause ontstond. Dat komt doordat Java de hele applicatie even stillegt om de laatste stappen van het opruimen van de ontstane memory garbage op te ruimen. Afhankelijk van je taak is dat natuurlijk niet per se een probleem; dat geheugen moet toch een keer opgeruimd worden.

Bij ons kwam het daardoor echter voor dat zo'n Engine meer dan twee seconden onbereikbaar was. Het opgeruimd houden van 8GB geheugen kost helaas aardig wat tijd, zelfs op onze snelle hardware. Doordat onze PHP-code automatisch naar een andere Engine verbindt als het te lang duurt, merk je daar als gebruiker verder weinig van, maar het was geen ideale situatie. Met de Concurrent Mark Sweep garbage collector is dat verleden tijd geworden. Deze ruilt een beetje opruimkwaliteit in voor een veel gunstiger pauzeregime. In technische termen: de maximale throughput is wat lager en het geheugen wordt iets minder goed opgeruimd, maar in ruil daarvoor zijn de latencypieken ook veel lager geworden.

ActiveMQ

We gebruiken ActiveMQ, via het Stomp-protocol, om bepaalde zaken vanuit PHP uitgesteld te kunnen verwerken. Het is bijvoorbeeld nergens voor nodig om een logfile direct bij te werken tijdens een pageview, dat mag best een paar minuten later gebeuren. Door deze log-updates in een Message Queue in ActiveMQ te plaatsen zorgen we ervoor dat deze asynchroon met de pageview opgeslagen worden.

Daardoor hoeft niet bij elke pageview een verbinding gemaakt te worden met onze database om vervolgens een insert te doen. We kunnen bovendien tijdens het verwerken meteen verschillende van deze inserts groeperen. Daarnaast kunnen we zo het aantal processen dat tegelijk de data in de database bijwerkt beperken.

Een laatste groot voordeel is dat we de load van onze database kunnen monitoren en het tempo van de verwerking daarop kunnen aanpassen. Als de load stijgt, kunnen we het uitlezen van de message queues vertragen of zelfs tijdelijk pauzeren. Hierdoor kunnen we de invloed van het opslaan van log-gegevens en daarmee de hele databaseload (een beetje) beperken.

Omdat ActiveMQ zo belangrijk is bij elke pageview, willen we daarmee natuurlijk geen spof introduceren. Vandaar dat we ervoor gekozen hebben om met ActiveMQ een network of brokers op te zetten. In ons geval betekent dit dat iedere webserver een eigen ActiveMQ draait en dat deze de inkomende berichten doorstuurt naar een van twee centrale brokers. De consumers maken verbinding met die centrale instanties om de berichten uit te lezen en te verwerken.

De PHP-code op de webservers probeert eerst de berichten naar de lokale instantie te verzenden, die is tenslotte het snelst te bereiken. Mocht dat niet lukken, dan wordt een van de centrale instanties geprobeerd. Door deze opstelling kunnen de berichten op de lokale server gebufferd worden voordat ze naar de centrale message queue worden verzonden. Al met al moet dat ertoe leiden dat we vrij eenvoudig de verwerking van berichten kunnen pauzeren, vertragen of naar een andere server verhuizen, zonder dat de webservers, en dus de bezoekers, daar last van hebben.

Wat vind je van dit artikel?

Geef je mening in het Geachte Redactie-forum.

Apple iPad Pro (2021) 11" Wi-Fi, 8GB ram Microsoft Xbox Series X LG CX Google Pixel 5a 5G Sony XH90 / XH92 Samsung Galaxy S21 5G Sony PlayStation 5 Nintendo Switch Lite

Tweakers vormt samen met Hardware Info, AutoTrack, Gaspedaal.nl, Nationale Vacaturebank, Intermediair en Independer DPG Online Services B.V.
Alle rechten voorbehouden © 1998 - 2021 Hosting door True