...

Optimiser le cache de threads de MariaDB : des performances accrues avec moins de surcharge

Je configure spécifiquement le cache de threads de MariaDB afin d'optimiser l'établissement des connexions et la création de threads. Cela me permet de réduire Latence et faire des économies CPU‑Surcharge, notamment en cas de nombreuses sessions courtes et d'un taux de connexion élevé.

Points centraux

Les aspects suivants constituent les lignes directrices pour un réglage et une mesure efficaces du cache. Je me concentre sur des Valeurs et applicables Étapes.

  • Principe d'action: Réutilisation des threads terminés plutôt que leur recréation, plus coûteuse
  • Pertinence: Utile en cas de nombreuses connexions courtes par seconde
  • Mesure: Threads_created, Connections, Threads_cached
  • Frontières: Ignoré si le pool de threads est actif
  • Procédure: Commencer modestement, évaluer, augmenter progressivement

Voici comment fonctionne le cache de threads de MariaDB

Une fois la connexion fermée, MariaDB place le thread dans un cache tant que la limite n’est pas atteinte. Les nouvelles connexions peuvent réutiliser ce thread, ce qui évite de devoir le recréer (opération coûteuse) et permet d’ Temps de réponse réduit. Cela est particulièrement efficace en cas de nombreux connexions par seconde et de charges de travail comportant des sessions courtes, dans lesquelles la création et la destruction de threads entraînent un ralentissement perceptible Facteur de coûts . Le cache se vide après environ cinq minutes d'inactivité, ce qui évite au serveur d'accumuler des données obsolètes inutiles. Sans pool de threads, la valeur par défaut est souvent de 256, ce qui offre une petite marge pour les pics de trafic habituels. Je note par ailleurs que la réutilisation ne résout pas tous les problèmes : une mauvaise connexion ou des stratégies client défaillantes restent visibles et nécessitent des corrections spécifiques.

Quand le tuning en vaut la peine

J'augmente la taille du cache lorsque l'application établit de nombreuses connexions de courte durée et que le compteur Threads_created connaît une croissance fulgurante. Un indicateur clair est un ratio élevé entre le nombre de threads créés (Threads_created) et le nombre de connexions (Connections) : cela signifie que la réutilisation manque trop souvent son objectif. Dans ce cas, les nouveaux threads réduisent la CPU et alourdissent le temps de réponse, tandis que la réutilisation raccourcit le chemin d'accès. Je vérifie toutefois toujours si la cause ne se situe pas du côté du client, par exemple à cause de reconnexions inutiles. Si une gestion correcte des connexions permet de stabiliser la charge, le cache ne nécessite souvent qu'un ajustement modéré. Ceux qui maximisent à l’aveuglette en paient rapidement le prix en termes de consommation de mémoire et négligent les véritables leviers d’optimisation dans la logique de l’application.

Valeurs mesurées que je vérifie au préalable

Pour établir un diagnostic précis, j'utilise un nombre restreint d'indicateurs pertinents, calculés à l'aide de formules claires. Pour commencer, je lis Threads_created, Connections, Threads_cached et Threads_connectés et j'analyse les tendances. Le simple ratio Threads_created/Connections m'indique à quelle fréquence la base de données se reconstruit au lieu de réutiliser les connexions existantes. La proximité de la valeur Threads_cached par rapport au pic habituel de connexions simultanées est également très utile. Si l'écart entre la valeur du cache et le pic reste important, je Ressources ou rencontre la Dernier Non. Le tableau suivant rassemble les indicateurs clés et leur signification directe :

Chiffre clé Signification interprétation Action
Threads_created Fils de discussion créés depuis le démarrage Une croissance rapide indique une régénération fréquente Vérifier le cache, réduire les reconnexions des clients
Connections Nombre total de connexions Base de calcul du taux et d'évaluation de la tendance Suivre l'évolution des pics de charge
Threads_cached Threads en cache Une valeur faible malgré une fréquence élevée peut être insuffisante Augmenter le cache par petites étapes
Threads_connectés Connexions actuellement actives Indication pour déterminer une taille de cache appropriée Dimensionner le cache en fonction des pics typiques

Adaptation progressive dans la pratique

Je commence par effectuer des mesures sous une charge réaliste et je note les indicateurs clés avant chaque modification. Ensuite, je vérifie la valeur actuelle à l'aide de SHOW VARIABLES LIKE 'thread_cache_size' et note le Base pour plus tard Comparaisons. J'augmente ensuite par petites étapes et j'observe si la valeur de « Threads_created » augmente plus lentement et si les temps de connexion se stabilisent. Un seul changement important masque les causes, c'est pourquoi je mise délibérément sur des étapes petites et vérifiables. Après chaque ajustement, j’attends une phase de charge significative afin que l’effet reste fiable. Ce n’est que lorsque plusieurs fenêtres de charge confirment le résultat que j’envisage l’étape suivante.

Logique de réglage recommandée et valeurs initiales

Il n'existe pas de valeur idéale universelle ; je me base donc sur les pics habituels et l'historique. Pour des débits de connexion faibles ou moyens, un cache de petite à moyenne taille suffit souvent, notamment si l'on s'en tient à la norme de 256. En cas de forte fluctuation de la charge et d'un nombre élevé de connexions par seconde, une taille de cache plus importante est utile, à condition que le taux de réutilisation augmente réellement. Je maintiens la taille du cache légèrement en dessous des pics habituels de Threads_connected, afin d'éviter tout Ressources je limite. Ceux qui agrandissent excessivement le cache gaspillent de la mémoire sans en tirer aucun avantage. De plus, je tiens compte des threads d'arrière-plan associés, tels que le Fils de discussion sur Page Cleaner, car elles influencent elles aussi le comportement global en cas d'activité E/S élevée.

Besoins en mémoire par thread et incidence de la taille du cache

Je tiens délibérément compte de l'effet de mémoire du cache. Un thread mis en cache conserve principalement son thread_stack et peu de métadonnées de thread. Des tampons par connexion tels que sort_buffer_size, join_buffer_size ou la mémoire tampon réseau sont libérées lors de la déconnexion et ne surchargent pas le cache de manière permanente. La pile, en revanche, reste liée au thread. À titre indicatif, je pars du principe que : Mémoire cache ≈ thread_cache_size × thread_stack (plus un petit supplément). Dans le cas d'un thread_stack Avec 256 à 320 Ko et un cache de 512, cela représente déjà environ 130 à 170 Mo de mémoire allouée. Si vous augmentez la taille de la pile ou utilisez des caches très volumineux, vous devez garder cet effet à l’esprit et le mettre en balance avec des tampons plus importants (par exemple, les tampons InnoDB).

C'est pourquoi je vérifie toujours :

  • SHOW VARIABLES LIKE 'thread_stack'; pour connaître la mémoire allouée par thread
  • La proximité de Threads_cached au pic du 95e centile de Threads_connectés
  • À savoir si l'augmentation de la taille du cache a un impact sur le taux Threads_created / Connexions réellement amélioré

Si cela n'apporte aucun avantage, je réduirai à nouveau la taille du cache. Un cache trop grand se reconnaît au fait que Threads_cached reste constamment supérieur au pic habituel de connexion, sans que les latences ne continuent à diminuer.

Fonctionnement sous Linux et dans des conteneurs : limites et obstacles

Je vérifie les limites au niveau du système avant d'augmenter la taille du cache. La création de threads peut échouer en raison des limites du système d'exploitation bien avant que la base de données elle-même n'atteigne son nombre maximal de connexions. Je vérifie donc les éléments suivants :

  • Limites des processus et des threads: ulimit -u (nombre maximal de processus/threads), /proc/sys/kernel/threads-max et /proc/sys/kernel/pid_max
  • Limite de la pile: ulimit -s influe sur la taille de la pile réservée par thread – ce qui est globalement important pour les caches de grande taille
  • cgroups dans le conteneur: pids.max et les limites de mémoire ; des limites PID trop strictes freinent les rafales
  • Impression du planificateur: Lorsque le nombre de threads sans pool est très élevé, la surcharge liée aux changements de contexte peut augmenter ; dans ce cas, il peut être plus judicieux d’utiliser un pool de threads ou le « pool d’applications »

Sur les hôtes multi-sockets ou NUMA, je vérifie également si des threads passent d’un nœud à l’autre, ce qui entraîne des accès à la mémoire à distance. Dans de tels environnements, les pools stables sont souvent plus efficaces que la création constante de nouveaux threads, qui sont largement répartis par le planificateur.

Idées reçues courantes concernant le cache de threads

Je dissipe les idées reçues afin d'optimiser de manière ciblée :

  • „ Plus de mémoire cache = toujours plus rapide. “ Ce n'est que si de nombreux nouveaux fils de discussion sont effectivement créés que le cache s'avère avantageux. Sinon, je mobilise de la mémoire sans en tirer aucun bénéfice.
  • „ Le cache accélère l'authentification. “ Le cache permet avant tout d’éviter la création de threads du système d’exploitation. L’authentification, la négociation TLS et, le cas échéant, les requêtes DNS ont lieu à chaque connexion et restent, indépendamment de cela, des éléments à optimiser.
  • „ Les tampons par thread restent occupés. “ Après la déconnexion, ces zones tampons sont libérées ; il ne reste principalement dans le cache que la pile du thread.
  • „ Un cache volumineux remplace le regroupement d'applications. “ Le cache côté serveur permet de réduire les coûts, mais le regroupement côté application permet de les éviter. Je considère toujours le regroupement d'applications comme la première solution à envisager.

Impact du protocole TLS, du DNS et de l'authentification

J'analyse les temps de connexion de manière nuancée, car le cache ne couvre pas toutes les parties. Élevé Durées de la poignée de main j'attribue souvent cela à un problème lié au protocole TLS (vérification du certificat, absence de reprise) ou à la résolution DNS inversée. Avec skip_name_resolve=ON J'évite les recherches inversées coûteuses et je m'appuie sur des autorisations basées sur l'adresse IP. Le choix et la configuration du plugin d'authentification influencent également le chemin d'authentification. Le cache de threads, en revanche, réduit principalement le coût de Création et destruction de threads. Si, malgré un cache important, je constate que les latences de connexion restent élevées, je me concentre sur les paramètres TLS, le DNS et la gestion des connexions client.

Logique de décision : cache, pool de threads ou pool d'applications ?

Je prends ma décision en suivant un chemin simple :

  • Le regroupement d'applications est-il disponible ? Si oui, bien dimensionner. S'enfonce Threads_created Il apparaît clairement qu'un cache de petite à moyenne taille suffit comme tampon.
  • Le pool de threads est-il actif ? C'est alors que intervient thread_cache_size Non. Je règle le pool et je mesure les temps d'attente avant de modifier d'autres paramètres.
  • Beaucoup de relations de courte durée sans « pool » ? Augmenter modérément la mémoire cache. Objectif : une baisse sensible du taux Threads_created / Connexions et des moments de connexion plus calmes.
  • Un niveau de parallélisme très élevé et une forte pression sur le planificateur ? J'étudie la possibilité de passer au pool de threads, qui peut permettre le « work stealing » et offrir des quotas de workers plus restreints.

Ce qui importe, c'est le plan de repli : si une approche ne s'avère pas nettement plus efficace, je reviens à la dernière modification. Je reste ainsi proche des données et j'évite toute complexité sans valeur ajoutée.

Méthodologie de mesure avec des exemples de requêtes

J'utilise des requêtes reproductibles pour mesurer les progrès. Voici un aperçu :

  • SHOW GLOBAL STATUS LIKE 'Threads\_%'; fournit Threads_created, Threads_cached, Threads_connectés
  • SHOW GLOBAL STATUS LIKE 'Connections' ; pour la base de calcul du quota
  • SHOW VARIABLES LIKE 'thread\_%' ; à l'adresse suivante : thread_cache_size et thread_stack à vérifier

Je calcule ce taux, par exemple, de la manière suivante :

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';

Pour les tests de charge, j'utilise des plages horaires. Je prends deux instantanés (au début et à la fin d'un intervalle de 5 à 10 minutes) et je calcule les différences. En option, j'utilise un environnement de test isolé ÉTAT DE LA VIDANGE, pour réinitialiser les compteurs – en production, j’évite de le faire afin de ne pas perturber d’autres analyses. Outre le taux, j’enregistre les 95e et 99e centiles de la durée de connexion issus de la surveillance des clients, car c’est précisément là que se manifestent les effets sur les pics de latence.

Identifier le problème : la mémoire cache est trop petite

Je détecte souvent qu'un cache est trop petit lorsque le nombre de threads créés (Threads_created) augmente fortement alors que la charge reste constante. Dans le même temps, le nombre de threads mis en cache (Threads_cached) reste faible, bien que le système traite de nombreuses connexions et que le taux de mise en cache soit médiocre. Il en résulte des fluctuations Latence et inutiles CPU‑Surcharge due à la création fréquente de threads. Si le cache augmente modérément et que les indicateurs se stabilisent, cela confirme le diagnostic. Si les temps s'améliorent et que le taux s'améliore nettement, c'est que je suis sur la bonne voie. Si l'effet ne se produit pas, je recherche de manière ciblée les causes liées aux clients, les problèmes réseau ou les goulots d'étranglement au niveau du stockage.

Identification : la mémoire cache est trop grande

Un cache trop volumineux passe plus facilement inaperçu, mais peut monopoliser de la mémoire dont d'autres cibles de mise en cache ont besoin. Je constate alors un taux déjà satisfaisant, mais augmenter la taille du cache ne change pratiquement rien et ne fait que surcharger la Ressources. Si la valeur de Threads_cached reste durablement bien au-dessus du pic habituel, l'avantage disparaît. Je réduis progressivement cette valeur et je vérifie si les indicateurs ou les temps de réponse évoluent. Si tout reste stable, j’opte pour la configuration la plus petite et la plus efficace. Je maintiens ainsi l’instance allégée et je laisse de la place pour des zones de mémoire plus importantes, telles que le tampon InnoDB et les structures de remplacement du cache de requêtes.

Particularité : pool de threads actif

Dès que le pool de threads est en cours d'exécution, MariaDB ignore complètement la variable thread_cache_size. Dans ce mode, un pool gère un petit nombre de threads de travail qui traitent un grand nombre de connexions, évitant ainsi les temps d'attente pour les nouveaux threads. Je décide, en fonction du profil de charge, s'il convient de mettre en place un pooling des bon L'approche consiste à... ou le cache est plus... Flexibilité fournit. Les charges de travail fortement parallélisées tirent souvent parti du pool, tandis que les pics de connexion classiques fonctionnent bien grâce à la réutilisation du cache. Ceux qui utilisent le pool se concentrent sur ses paramètres et ne tiennent pas compte de la variable `thread_cache_size`. Un bon point de départ consiste à consulter la documentation sur le Pool de threads MariaDB, avant de prévoir d'autres étapes de mise au point.

Interaction avec la gestion du pool de connexions de l'application

Je préfère un pool côté application, car il maintient les connexions ouvertes et soulage le serveur de base de données. Si la valeur de `Threads_created` reste faible malgré une charge élevée, cela indique que le pooling est efficace et que le besoin en cache supplémentaire est faible. Dans cette configuration, un petit cache suffit souvent pour amortir les pics occasionnels et ne nécessite pas Ressources gaspillées. En revanche, si je constate des reconnexions constantes, il faut d’abord optimiser la gestion des pools d’applications, puis augmenter la configuration de la base de données. L’analyse des temps d’inactivité et de la taille des pools permet de trouver le juste équilibre pour une charge uniforme. Un guide pratique fournit des informations utiles pour débuter sur Mise en commun des connexions, que j'utilise en parallèle de l'optimisation du cache.

Exemple : configuration et contrôle

Je commence par vérifier le réglage actuel avec SHOW VARIABLES LIKE 'thread_cache_size' et je note la charge. Ensuite, je définis à titre d'essai une valeur modérée telle que SET GLOBAL thread_cache_size = 256; ou 512, selon les cas. Il est important d'apporter une modification permanente dans le fichier de configuration, par exemple dans my.cnf à l'adresse suivante : [mysqld], afin que le redémarrage conserve le réglage. Dans les fenêtres de charge suivantes, j'observe Threads_created et la Citation, jusqu'à ce que je constate une tendance claire. Si le nombre de nouvelles créations diminue nettement, cela signifie que le cache atteint son objectif. Si les chiffres restent inchangés, je cherche les causes au niveau de la gestion des connexions avant d'augmenter encore la valeur.

Guide pratique : dimensionnement à l'aide de lignes directrices

Je m'appuie sur des valeurs de référence fiables plutôt que de chercher aveuglément à maximiser :

  • Lancement: Meilleurs résultats actuels de Threads_connectés observer (sur plusieurs fenêtres de charge typiques).
  • Premier dimensionnement: Cache ≈ 70 à 90 % du pic habituel, avec en outre un plafond tel que max_connections / 2 comme limite de sécurité.
  • Incrément: Augmenter par petits paliers de 64 à 128 et le taux Threads_created / Connexions vérifier.
  • fourchette cible: Baisse significative du taux et stabilisation des 95e centiles des temps de connexion ; si l'effet ne se produit pas, réduire la taille du cache.
  • Persistance: À partir des versions de MariaDB comprenant SET PERSIST j'enregistre les valeurs vérifiées directement côté serveur, sinon dans my.cnf.
  • Retour en arrière: Avant chaque modification, je note la valeur précédente afin de pouvoir revenir rapidement en arrière en cas de doute.

Dans les environnements présentant des profils jour/nuit très contrastés, je recommande un dimensionnement prudent qui lisse les pics sans mobiliser inutilement trop de mémoire pendant la nuit. Pour les charges exceptionnelles (déploiements, vagues de tâches Cron), je prévois délibérément des marges de sécurité.

Liste de contrôle pour le dépannage

Je vérifie d'abord si le pool de threads est actif et, par conséquent, s'il désactive le cache. Ensuite, je mesure le rapport Threads_created/Connections sur plusieurs intervalles de temps, plutôt que de me contenter d'un simple instantané. Je compare ensuite Threads_cached au pic de Threads_connected afin de détecter un surdimensionnement ou un sous-dimensionnement. Si les performances restent faibles, j’examine les reconnexions de l’application, les latences réseau et les signaux de stockage tels que l’augmentation des temps d’attente d’E/S. Pour finir, j’examine les paramètres concurrents qui influencent les threads et je propose des scénarios de test reproductibles. C’est la seule façon de tirer des conclusions claires et d’éviter de prendre des mesures précipitées sans base de données solide.

Version courte pour les personnes pressées

J'utilise le cache de threads pour réutiliser les threads et réduire les coûts de création. Cela est particulièrement efficace lorsque la fréquence des connexions est élevée, tandis qu'un pool de threads actif ignore cette variable. Le succès se mesure par la baisse du taux de Threads_created à Connections et des temps de connexion plus réguliers. Je commence modestement, je mesure systématiquement les performances et je n’augmente les paramètres que si les chiffres et le profil le justifient. Le regroupement côté client reste souvent le levier le plus efficace, c’est pourquoi je commence par l’examiner. Je parviens ainsi à améliorer les performances avec moins de surcharge et à conserver une configuration allégée.

Derniers articles