...

MariaDB-threadcache efficiënt instellen: betere prestaties met minder overhead

Ik stel de MariaDB-threadcache specifiek in om het tot stand brengen van verbindingen en het aanmaken van threads te vertragen. Zo verlaag ik Latency en bespaar CPU‑Overhead, vooral bij veel korte sessies en een hoge verbindingssnelheid.

Centrale punten

De volgende aspecten vormen de richtlijnen voor een effectieve instelling en meting van de cache. Ik concentreer me op duidelijke Waarden en toepasbare Stappen.

  • Werkingsprincipe: Hergebruik van afgesloten threads in plaats van het kostbaar aanmaken van nieuwe
  • Relevantie: Handig bij veel korte verbindingen per seconde
  • Meting: Threads_created, Connections, Threads_cached
  • Grenzen: Wordt genegeerd als de threadpool actief is
  • Procedure: Klein beginnen, meten, voorzichtig opvoeren

Zo werkt de MariaDB-threadcache

Nadat een verbinding is verbroken, plaatst MariaDB de thread in een cache, zolang de limiet nog niet is bereikt. Nieuwe verbindingen kunnen deze thread opnieuw gebruiken, waardoor het kostbare aanmaken ervan wordt vermeden en de Reactietijd verlaagt. Dit is vooral merkbaar bij veel aanmeldingen per seconde en bij workloads met korte sessies, waarbij het aanmaken en vernietigen van threads een merkbare Kostenfactor wordt. De cache wordt na ongeveer vijf minuten inactiviteit geleegd, waardoor de server geen onnodige oude gegevens opslaat. Zonder threadpool ligt de standaardwaarde vaak op 256, wat een kleine buffer biedt voor typische pieken. Ik merk bovendien op dat hergebruik niet alle problemen oplost: slechte verbindingen of foutieve clientstrategieën blijven zichtbaar en vereisen aparte correcties.

Wanneer is tuning de moeite waard?

Ik vergroot de cache als de applicatie veel korte verbindingen tot stand brengt en de teller Draden_aangemaakt groeit razendsnel. Een duidelijk signaal is een hoge verhouding tussen Threads_created en Connections, want dan schiet hergebruik te vaak zijn doel voorbij. In dat geval drukken nieuwe threads de CPU en vertragen de responstijd, terwijl Reuse het pad verkort. Ik controleer echter altijd of de oorzaak niet bij de client ligt, bijvoorbeeld door onnodige herverbindingen. Als een nette afhandeling van de verbindingen de belasting vermindert, is vaak slechts een bescheiden aanpassing van de cache nodig. Wie blindelings maximaliseert, betaalt daar al snel voor met geheugengebruik en ziet de echte knoppen in de applicatielogica over het hoofd.

Meetwaarden die ik vooraf controleer

Voor een nauwkeurige diagnose maak ik gebruik van een klein aantal, maar veelzeggende kengetallen met duidelijke formules. Om te beginnen lees ik Draden_aangemaakt, Verbindingen, Threads_cached en Draden_verbonden en bekijk ik trends. De eenvoudige verhouding Threads_created/Connections laat me zien hoe vaak de database opnieuw wordt opgebouwd in plaats van hergebruikt. Ook erg nuttig is de afstand tussen Threads_cached en het gebruikelijke piekgetal van gelijktijdige verbindingen. Als de cache en de afstand tot de piek groot blijven, geef ik Bronnen of ontmoet de Belasting Nee. In de onderstaande tabel zijn belangrijke kengetallen en hun directe betekenis samengevat:

Sleutelfiguur Dat betekent Interpretatie Actie
Draden_aangemaakt Nieuw aangemaakte threads sinds de start Snelle groei duidt op frequente nieuwe vorming Cache controleren, het aantal herverbindingen van clients verminderen
Verbindingen Totaal aantal verbindingen Basis voor quotum en trendanalyse De ontwikkeling van de piekbelasting in de gaten houden
Threads_cached Threads in de cache Een lage waarde, ondanks een hoge frequentie, kan te laag zijn De cache in kleine stapjes vergroten
Draden_verbonden Momenteel actieve verbindingen Richtlijn voor een geschikte cachegrootte De cache afstemmen op typische pieken

Stapsgewijze aanpassing in de praktijk

Ik begin met een meting onder realistische belasting en noteer de kerncijfers vóór elke wijziging. Vervolgens controleer ik de huidige waarde met SHOW VARIABLES LIKE 'thread_cache_size' en noteer de Basis voor later Vergelijkingen. Vervolgens verhoog ik de waarde in kleine stapjes en kijk ik of ‘Threads_created’ langzamer stijgt en de verbindingstijden stabieler worden. Eén grote wijziging verhult de oorzaken, daarom kies ik bewust voor kleine, controleerbare stappen. Na elke aanpassing wacht ik op een representatieve belastingfase, zodat het effect betrouwbaar blijft. Pas als meerdere belastingvensters het beeld bevestigen, overweeg ik de volgende stap.

Aanbevolen instellingslogica en startwaarden

Er bestaat geen universele ideale waarde, daarom baseer ik me op typische pieken en de geschiedenis. Voor lage of gemiddelde verbindingssnelheden volstaat vaak een kleine tot middelgrote cache, vooral dicht bij de standaard van 256. Bij sterk schommelende belasting en veel verbindingen per seconde helpt een grotere marge, zolang het hergebruik daadwerkelijk toeneemt. Ik houd de cache iets onder de gebruikelijke pieken van Threads_connected, zodat ik geen onnodige Bronnen koppel. Wie de cache enorm groot maakt, verspilt geheugen zonder daar voordelen uit te halen. Daarnaast let ik op bijbehorende achtergrondprocessen zoals de Page Cleaner-discussies, want ook zij zijn van invloed op het totale gedrag bij hoge I/O-activiteit.

Geheugenbehoefte per thread en gevolgen van de cachegrootte

Ik houd bewust rekening met het cache-effect. Een thread in de cache behoudt in de eerste plaats zijn thread_stack en beperkte thread-metadata. Buffers per verbinding zoals sorteer_buffer_grootte, samenvoegen_buffer_grootte of de netwerkbuffer wordt bij het verbreken van de verbinding vrijgegeven en belast de cache niet permanent. De stack blijft daarentegen aan de thread gekoppeld. Als vuistregel ga ik uit van: Cachegeheugen ≈ thread_cache_size × thread_stack (plus wat overhead). Bij een thread_stack met 256–320 KB en een cache van 512 komt dat al neer op ongeveer 130–170 MB aan gebonden geheugen. Wie de stack vergroot of zeer grote caches gebruikt, moet dit effect in de gaten houden en afwegen tegen belangrijkere buffers (bijv. InnoDB-buffers).

Daarom controleer ik altijd:

  • SHOW VARIABLES LIKE 'thread_stack'; om te weten hoeveel geheugen er per thread wordt gebruikt
  • De nabijheid van Threads_cached naar het 95e percentiel van Draden_verbonden
  • Of de vergroting van de cache het percentage Aantal aangemaakte threads / Aantal verbindingen daadwerkelijk verbeterd

Als het voordeel uitblijft, verklein ik de cache weer. Een te grote cache is te herkennen aan het feit dat Threads_cached blijvend boven de gebruikelijke piekwaarde ligt, zonder dat de latentie verder afneemt.

Gebruik op Linux en in containers: beperkingen en valkuilen

Ik controleer de systeembrede limieten voordat ik de cache vergroot. Het aanmaken van threads kan mislukken vanwege beperkingen van het besturingssysteem, lang voordat de database zelf het maximale aantal verbindingen bereikt. Daarbij controleer ik het volgende:

  • Proces-/threadgrenzen: ulimit -u (max. processen/threads), /proc/sys/kernel/threads-max en /proc/sys/kernel/pid_max
  • Stacklimiet: ulimit -s heeft invloed op de per thread gereserveerde stack – in totaal van belang voor grote caches
  • cgroups in de container: pids.max en geheugenlimieten; te krappe PID-grenzen remmen bursts af
  • Afdrukken via de planner: Bij een zeer groot aantal threads zonder pool kan de overhead door contextwisselingen toenemen; in dat geval kan het gebruik van een threadpool of app-pooling zinvoller zijn

Op multi-socket- of NUMA-hosts let ik er bovendien op of threads van de ene node naar de andere springen en daardoor toegang tot geheugen op afstand veroorzaken. In dergelijke omgevingen zijn stabiele pools vaak efficiënter dan voortdurend nieuwe threads die door de scheduler wijdverspreid worden ingezet.

Veelvoorkomende misvattingen over de threadcache

Ik ruim veelvoorkomende misvattingen uit de weg om doelgericht te optimaliseren:

  • „Meer cache = steeds sneller.“ Alleen als er daadwerkelijk veel nieuwe threads worden aangemaakt, levert de cache voordeel op. Anders leg ik geheugen vast zonder dat het iets oplevert.
  • „De cache versnelt de authenticatie.“ De cache bespaart in de eerste plaats het aanmaken van OS-threads. Authenticatie, de TLS-handshake en eventueel DNS-lookups vinden per verbinding plaats en moeten nog steeds afzonderlijk worden geoptimaliseerd.
  • „De buffers per thread blijven bezet.“ Na het verbreken van de verbinding worden deze buffers vrijgegeven; in de cache blijft voornamelijk de stack van de thread achter.
  • „Een grote cache vervangt app-pooling.“ Caching aan de serverzijde drukt de kosten, maar pooling aan de app-zijde voorkomt ze. Ik beschouw app-pooling altijd als de eerste maatregel die ik overweeg.

Invloed van TLS, DNS en authenticatie

Ik bekijk de verbindingstijden op verschillende manieren, omdat de cache niet elk onderdeel opslaat. Hoge Tijden voor de handdruk interpret ik dit vaak als een TLS-probleem (certificaatcontrole, ontbrekende heropname) of DNS-omgekeerde resolutie. Met skip_name_resolve=ON Ik vermijd dure reverse-lookups en maak gebruik van op IP gebaseerde toewijzingen. Ook de keuze en configuratie van de auth-plugin beïnvloeden het inlogtraject. De thread-cache vermindert daarentegen vooral de kosten van Het aanmaken en verwijderen van threads. Als ik ondanks een grote cache nog steeds hoge Connect-latenties zie, richt ik mijn aandacht op TLS-parameters, DNS en het beheer van de clientverbindingen.

Beslissingslogica: cache, threadpool of app-pooling?

Ik volg een eenvoudig pad bij het nemen van mijn beslissing:

  • Is app-pooling beschikbaar? Zo ja, zorg dan voor de juiste afmetingen. Daalt Draden_aangemaakt Het is duidelijk dat een kleine tot middelgrote cache als buffer volstaat.
  • Is de threadpool actief? Dan treedt thread_cache_grootte Nee. Ik optimaliseer het pool en meet de wachttijden voordat ik andere instellingen aanpas.
  • Veel korte verbindingen zonder pool? De cache gematigd vergroten. Doel: een merkbaar dalend percentage Aantal aangemaakte threads / Aantal verbindingen en rustigere Connect-tijden.
  • Zeer hoge mate van parallelliteit en druk op de scheduler? Ik onderzoek de overstap naar de threadpool, die work-stealing en kleinere worker-quota’s kan bieden.

Belangrijk is het terugvalplan: als een aanpak niet aantoonbaar beter werkt, draai ik de laatste wijziging terug. Zo blijf ik dicht bij de gegevens en voorkom ik onnodige complexiteit.

Meetmethode met voorbeeldvragen

Ik gebruik reproduceerbare zoekopdrachten om de voortgang aan te tonen. Voor een momentopname:

  • SHOW GLOBAL STATUS LIKE 'Threads\_%'; benodigdheden Draden_aangemaakt, Threads_cached, Draden_verbonden
  • SHOW GLOBAL STATUS LIKE 'Connections'; als basis voor het quotum
  • SHOW VARIABLES LIKE 'thread\_%'; op thread_cache_grootte en thread_stack te controleren

Ik bereken het percentage bijvoorbeeld als volgt:

SELECT 
  ROUND(tc.variable_value+0 / NULLIF(c.variable_value+0,0), 4) AS threads_created_per_connection
FROM information_schema.GLOBAL_STATUS tc
JOIN information_schema.GLOBAL_STATUS c
  ON tc.variable_name='Threads_created' AND c.variable_name='Connections';

Voor belastingstests maak ik gebruik van tijdvensters. Ik neem twee momentopnames (het begin en het einde van een interval van 5 tot 10 minuten) en bereken de verschillen. Optioneel maak ik gebruik van een geïsoleerde testomgeving FLUSH-STATUS, om tellers te resetten – in de productie vermijd ik dat, om andere analyses niet te verstoren. Naast het percentage sla ik het 95e en 99e percentiel van de verbindingsduur uit de clientmonitoring op, want juist daar worden de effecten op de latentiepieken zichtbaar.

Herkennen: de cache is te klein

Ik merk vaak dat de cache te klein is doordat ‘Threads_created’ bij een constante belasting sterk stijgt. Tegelijkertijd blijft ‘Threads_cached’ laag, hoewel het systeem veel verbindingen verwerkt en de quota slecht uitvalt. Het gevolg is schommelende Latencies en onnodige CPU‑Belasting door het veelvuldig aanmaken van threads. Als de cache gematigd toeneemt en de statistieken zich stabiliseren, bevestigt dat de diagnose. Als de tijden stabieler worden en de ratio aanzienlijk verbetert, ben ik op de goede weg. Als het effect uitblijft, ga ik gericht op zoek naar oorzaken aan de kant van de client, netwerkproblemen of knelpunten in de opslag.

Herkennen: de cache is te groot

Een te grote cache valt minder snel op, maar kan wel geheugen in beslag nemen dat dan ontbreekt voor andere bufferdoelen. Ik meet dan al een goede score, maar meer cache verandert nauwelijks iets en belast alleen de Bronnen. Als Threads_cached permanent ver boven de gebruikelijke piek ligt, gaat het voordeel verloren. Ik verlaag de waarde stapsgewijs en controleer of de statistieken of responstijden veranderen. Als alles stabiel blijft, kies ik voor de kleinere, efficiëntere configuratie. Zo houd ik de instantie slank en laat ik ruimte over voor belangrijkere geheugengebieden zoals de InnoDB-buffer en vervangende query-cache-structuren.

Bijzonderheid: threadpool actief

Zodra de threadpool actief is, negeert MariaDB de variabele `thread_cache_size` volledig. In deze modus stuurt één pool een klein aantal workers aan, die veel verbindingen afhandelen en zo wachttijden voor nieuwe threads voorkomen. Ik beslis op basis van het belastingprofiel of het poolen van de rechts De aanpak is of de cache meer Flexibiliteit levert. Sterk geparalleliseerde workloads profiteren vaak van de pool, terwijl klassieke inlogpieken goed presteren met cachehergebruik. Wie de pool gebruikt, richt zich op de parameters ervan en laat `thread_cache_size` buiten beschouwing. Een goed startpunt is het lezen van de MariaDB-threadpool, voordat ik verdere afstemmingsstappen plan.

Interactie met de connection pooling van de applicatie

Ik geef de voorkeur aan een pool in de app, omdat deze verbindingen openhoudt en de database-server ontlast. Als `Threads_created` ondanks een hoge belasting laag blijft, wijst dit op effectieve pooling en een geringe behoefte aan extra cache. In deze opstelling volstaat vaak een kleine cache die incidentele pieken opvangt en geen Bronnen verspild. Als ik daarentegen voortdurend herverbindingen zie, moet ik eerst zorgen voor een goede app-pooling en pas daarna de database-instellingen aanpassen. Door te kijken naar de inactieve tijden en de grootte van de pools kun je de ideale balans vinden voor een gelijkmatige belasting. Een praktische handleiding biedt nuttige basisinformatie over Poolen van verbindingen, die ik naast de cache-optimalisatie gebruik.

Voorbeeld: configuratie en controle

Ik controleer eerst de huidige instelling met SHOW VARIABLES LIKE 'thread_cache_size' en leg de belasting vast. Daarna stel ik bij wijze van test een gematigde waarde in, zoals SET GLOBAL thread_cache_size = 256; of 512, afhankelijk van de punten. Het is belangrijk om deze wijziging permanent in het configuratiebestand aan te brengen, bijvoorbeeld in my.cnf op [Mysqld], zodat de instelling na het opnieuw opstarten behouden blijft. In de volgende belastingvensters zie ik Draden_aangemaakt en de bijbehorende Citaat, totdat ik een duidelijke trend zie. Als de nieuwe productie aanzienlijk daalt, bereikt de cache zijn doel. Als de cijfers ongewijzigd blijven, zoek ik naar oorzaken in het verbindingsbeheer, voordat ik de waarde verder verhoog.

Praktijkgids: dimensionering met richtlijnen

Ik werk met realistische richtwaarden in plaats van blindelings te streven naar maximalisatie:

  • Start: Huidige pieken van Draden_verbonden observeren (over meerdere typische belastingsvensters).
  • Eerste dimensionering: Cache ≈ 70–90 % van de gebruikelijke piek, met daarnaast een bovengrens zoals max_connections / 2 als veiligheidslimiet.
  • Stapgrootte: Verhoog in kleine stappen van 64–128 en het percentage Aantal aangemaakte threads / Aantal verbindingen controleren.
  • Doelbereik: Aanzienlijk dalend percentage en stabielere 95e percentielen bij verbindingstijden; als het effect uitblijft, de cache terugzetten.
  • Volharding: Vanaf MariaDB-versies met SET PERSIST sla ik geteste waarden direct op de server op, anders in my.cnf.
  • Terugdraaien: Voordat ik een wijziging doorvoer, noteer ik de vorige waarde, zodat ik in geval van twijfel snel terug kan gaan naar de oude instelling.

In omgevingen met sterk wisselende dag- en nachtpatronen raad ik een conservatieve dimensionering aan, die pieken afvlakt zonder ’s nachts onnodig veel opslagruimte in beslag te nemen. Voor speciale belastingen (implementaties, cron-pieken) bouw ik bewust buffers in.

Checklist voor probleemoplossing

Ik controleer eerst of de threadpool actief is en daarmee de cache omzeilt. Vervolgens meet ik de verhouding tussen Threads_created en Connections in verschillende tijdsvensters, in plaats van slechts één momentopname te nemen. Vervolgens vergelijk ik Threads_cached met de piek van Threads_connected om te zien of er sprake is van over- of onderdimensionering. Blijft de prestatie zwak, dan onderzoek ik herverbindingen van de applicatie, netwerklatenties en opslagsignalen zoals verhoogde I/O-wachttijden. Tot slot controleer ik concurrerende instellingen die van invloed zijn op threads en lever ik herhaalbare testscenario’s. Alleen zo trek ik duidelijke conclusies en voorkom ik overhaaste maatregelen zonder een solide gegevensbasis.

Verkorte versie voor wie haast heeft

Ik gebruik de thread-cache om threads te hergebruiken en de aanmaakkosten te verlagen. Dit heeft effect bij een hoge verbindingsfrequentie, terwijl een actieve thread-pool deze variabele negeert. Het succes is meetbaar aan de hand van een dalend percentage van Draden_aangemaakt naar Verbindingen en rustigere verbindingstijden. Ik begin klein, meet consequent en verhoog alleen als de cijfers en het profiel dat rechtvaardigen. Pooling aan de clientzijde is vaak de belangrijkste hefboom, dus daar kijk ik eerst naar. Zo bereik ik betere prestaties met minder overhead en houd ik de configuratie slank.

Huidige artikelen