Een van de eenvoudigste manieren om de performantie van een drukke website te verbeteren is om caching toe te voegen. Er zijn verschillende manieren waarmee dit kan gebeuren: Je kan objecten cachen in code (met Memcached en Redis), of je kan de responses cachen met Varnish, Nginx of in dit geval met Apache’s mod_cache. Ik raad dit op zich niet aan in productie, maar omdat ik Apache gebruik als webserver leek het me een leuk experiment, zonder veel extra configuratie te moeten toevoegen.
Onze website voorbereiden
voor we kunnen beginnen met het configureren van mod_cache, moeten we zeker zijn dat onze website de nodige cache-control headers stuurt. Deze headers zijn nodig zodat mod_cache weet wat moet gecached worden, en voor hoelang.
Een absoluut minimum is het sturen van een header als “cache control: max-age=300” om een pagina te cachen voor 300 seconden. Als een leuke bonus zal de browser van een bezoeker deze pagina’s ook cachen. We kunnen ook s-maxage gebruiken in plaats van max-age, zodat enkel pagina’s gecached worden op een shared cache (mod_cache in ons geval)
Ik gebruik django, dus we kunnen een view decoreren met @cache_page of @cache_control. De @cache_page decorator zal de pagina ook cachen in de cache die in de settings.py geconfigureerd staat (zoals memcached) naast het sturen van de benodigde headers. De @cache_control header, voegt enkel de nodige headers toe
@cache_page(300)
def view(request):
...
@cache_control(max_age=300)
def view(request):
...
Mod_cache configureren
mod_cache configureren is best eenvoudig, maar het werkt niet “out of the box”, en elke omgeving heeft wat tweaking nodig. Zo draait mod_cache standaard in “Quick Handler” modus, waar het eigenlijk voor apache draait (en dus ook het meeste van de processing van apache overslaat). Dit wilt zeggen dat het sneller is, maar omdat het bepaalde processing overslaat kan het problemen geven zoals met mod_deflate.
Om mod_cache in te schakelen moeten we enkel het volgende uitvoeren
sudo a2enmod cache cache_disk
Vervolgens willen we ook de htcacheclean service starten, deze zorgt ervoor dat de cache opslag niet oneindig blijft groeien.
sudo systemctl enable --now apache-htcacheclean
Voeg vervolgens het volgende toe aan de vhost die je wilt cachen
# enable mod_cache_disk
CacheEnable disk /
# use 'CacheDisable <path>' to disable caching for a certain patch
# send cache headers
CacheHeader on
CacheDetailHeader on
# we want to cache entries up to a week on disk
CacheMaxExpire 604800
# No quick handler as we want mod_deflate to be in front of the cache layer
CacheQuickHandler off
SetOutputFilter CACHE
AddOutputFilterByType DEFLATE text/html text/plain text/css application/javascript application/rss+xml text/xml image/svg+xml
CacheIgnoreHeaders Cookie Set-Cookie
CacheIgnoreCacheControl On
# Thundering herd lock
CacheLock on
Performance testing
Om de performantie te testen, zal ik apachebench gebruiken. Er zijn “betere” tools voor performance testing, maar dit geeft ons een goed idee of de cache werkt.
ab -t 30 -c 50 -k -H 'accept-encoding: gzip' https://beta.skyz.be/nl/
- Zonder caching kan mijn server 339.98 requests/seconde verwerken
- Met caching, kan mijn server 1979.29 requests/seconde verwerken
WOW! Dat is een enorme verbetering. Al moeten we wel realistisch zijn dat in de praktijk er meer cache misses zullen zijn, en requests zullen zijn voor url’s die niet gecached zijn.