MYSQL - Recherche des causes de lenteur d'un serveur de base

De PedroWiki

Introduction

Cet article décrit l'ensemble des actions pouvant être menées pour détecter un problème ralentissant directement ou indirectement le fonctionnement d'une base mysql ou d'un serveur de base mysql.

Causes de lenteur d'un serveur MySQL

Causes réseau

Dans cette catégorie se classent les causes de ralentissement liées à des phénomènes de "goulet d'étranglement" au niveau TCP.

En synthèse, l'ensemble des accès aux différents ports TCP ouverts sur le serveur est si important que cela ralentit ou rend impossible (timeout) par la même occasion l'accès au port 3306.

Ces causes ne sont valables que pour une machine faisant office de serveur de base, i.e. dont le port 3306 écoute sur l'interface publique du serveur.

Causes système

Dans cette catégorie se classent les causes de ralentissement liées à des effets de bord engendrés par le fonctionnement global du système.

Si, sur la machine portant le serveur de bases, des processus systèmes non liés (*) provoquent une surcharge processeur, mémoire ou réseau (**) le serveur de bases peut encore une fois servir ses réponses plus lentement ou ne pas les servir du tout (timeout).

Un exemple typique de ce genre de causes est survenu lors de la mise en place de PHP-Syslog-NG sur un serveur faisant office de serveur de bases: les traitements de nettoyage de la base de donnée liée à Syslog-NG, lancés par la cron à intervalles très réguliers, se faisaient par l'intermédiaires de scripts PHP dont la compléxité était telle que la machine ne disposait pas d'assez de ressources processeur pour parvenir à traiter la demande. Ces ralentissements provoquaient par effet de ricochet de gros dysfonctionnement sur les services s'appuyant sur le serveur de bases puisque les requêtes de ces services ne pouvaient plus être traitées.

* ne faisant pas partie de l'ensemble des processus directement liés à MySQL

** impossibilité ou lenteur pour ouvrir un socket à destination du serveur de bases

Causes applicative

Causes liées au serveur

Dans cette catégorie se classent les causes de ralentissement liées à la configuration du service MySQL lui même.

Un exemple simple de ce genre de problème: laisser les logs activés. Les temps d'accès au disque pour logger les requêtes et les infos de fonctionnement du serveur induisent de grosses lenteurs dans le fonctionnement réel de MySQL (le service ne gère pas de requêtes quand il écrit sur le disque=.

Causes liées à la base de donnée

Dans cette catégorie se classent les causes de ralentissement liées à des problèmes de conception des accès aux bases et aux tables. On parle ici de problèmes spécifiques à MySQL et à des algorithmes associés.

On peut notamment provoquer des surcharges, et par conséquent des lenteurs voir des blocages, de MySQL quand on lui demande de faire des accès non optimisés aux tables: jointures en trop grand nombre, ou sur un trop grand nombre de tables.

L'exemple cité plus haut concernant PHP-Syslog-NG fait aussi partie de ces causes: outre la trop grande complexité des algorithmes implémentés en PHP, les requêtes de tri dans la base étaient elles aussi d'une trop grande complexité et provoquaient des lenteurs ou des refus d'accès à MySQL de ce fait.

On fait, dans ce type de cas, référence à des problèmes de slow queries ou requêtes lentes: la lourdeur d'exécution de ces requêtes entraine des latences dans les réponses du serveur de base. Ces latences sont paramétrables, quand on cherche à détecter de telles requêtes, en fonction des performances que l'on attend du serveur.

Méthodes de détection

Rapport MySQL

La commande mysqlreport permet d'obtenir un rapport d'utilisation de MySQL en temps réel.

L'idéal, pour exploiter le plus judicieusement possible ces rapports, est de disposer d'un rapport post-installation, alors que le SGBD est fraichement installé et qu'il est très peu sollicité. Cela permet d'avoir une "baseline" de comparaison, une référence.

Une autre solution quand on ne dispose pas de cette baseline est de comparer des rapports édités à 2 dates différentes pour pouvoir comparer les valeurs et observer des évolutions.

root@hikaru:~# mysqlreport --password --all
Password for database user root: ******
MySQL 5.0.38-Ubuntu_0ub  uptime 1 21:10:17      Wed Feb 25 09:00:59 2009

__ Key _________________________________________________________________
Buffer used   825.00k of  16.00M  %Used:   5.04
  Current       2.33M            %Usage:  14.57
Write ratio     0.619
Read ratio      0.003               <= 0.01 OK (1)

__ Questions ___________________________________________________________
Total           1.42M     8.7/s
[...]
  -Unknown        358     0.0/s            0.03
Slow          152.28k     0.9/s           10.76  %DMS:  51.75     %DMS <= 0.05 KO!!!!! (2)
DMS           294.24k     1.8/s           20.79
  SELECT      208.45k     1.3/s           14.73         70.84
  UPDATE       47.98k     0.3/s            3.39         16.31
  INSERT       24.21k     0.1/s            1.71          8.23
  DELETE       13.60k     0.1/s            0.96          4.62
  REPLACE           0       0/s            0.00          0.00
[...]

__ Table Locks _________________________________________________________
Waited          8.05k     0.0/s  %Total:   2.45            %Total <= 10% OK (3)
Immediate     320.33k     2.0/s

[...]
root@hikaru:~#

Commentaires:

  1. Si le Read Ratio dépasse la valeur de 0,01, cela signifie en général que le serveur manque de RAM, et qu'il est nécessaire d'en rajouter. Attention ceci dit à bien vérifier la capacité de sa version de MySQL à prendre en charge la quantité de RAM allouée.
  2. Par défaut, et sauf configuration explicite dans my.cnf, MySQL considère comme lente 1 requête prenant plus de 10 secondes. La dernière valeur sur la ligne (%DMS) devrait être inférieure à 0,05. Au dela d'une valeur de 0,30 la documentation indique qu'on doit se rendre compte de problèmes (sans préciser lesquels). C'est la valeur qu'il importe le plus de diminuer.
  3. Le verrouillage (lock) de tables est le mécanisme utilisé par MySQL pour permettre le partage de données entre des utilisateurs simultanés. Le pourcentage total de requêtes en attente de verrouillage de table (i.e. en attente d'exécution) doit d'après la documentation être inférieur à 10%, sans quoi cela implique de manière non ambigue la présence de Slow Queries.

Slow Queries

Mise en place du loggage

Comme indiqué sur la page dédiée aux requêtes lentes sur le site de MySQL, il y a plusieurs méthodes pour mettre en place la journalisation des requêtes lentes.

  1. par un passage d'option au démon lors de son lancement
  2. par la modification du fichier de configuration du démon

Ci dessous un extrait de my.cnf contenant les configurations essentielles à cette journalisation:

# * Logging and Replication
#
# Both location gets rotated by the cronjob.
# Be aware that this log type is a performance killer.
#log            = /var/log/mysql/mysql.log
#
# Error logging goes to syslog. This is a Debian improvement :)
#
# Here you can see queries with especially long duration
log_slow_queries        = /var/log/mysql/mysql-slow.log         NB: bien vérifier les droits sur ce fichier, si non loggage passer en 777 le temps des tests puis supprimer
long_query_time = 5
log-queries-not-using-indexes


Vérification des valeurs

Vérification de la présence de slow queries sur le serveur:

root@hikaru:~#  mysqladmin -p status
Enter password:
Uptime: 7588219  Threads: 14  Questions: 43446820  Slow queries: 112  Opens: 135009  Flush tables: 90  Open tables: 52  Queries per second avg: 5.726

Détermination du Top 10 des requêtes

  • Passer le long_query_time à 1 et redémarrer MySQL. Toutes les requêtes sont loggées.
  • Laisser ce loggage remplir le fichier pendant environ 1 journée.
  • Après cette journée, rechercher le top 10 des requêtes les plus lentes grâce à la commande mysqlsla.

Exemple de résultat de mysqlsla:

Report for slow logs: /var/log/mysql/mysql-slow.log
8.72k queries total, 53 unique
Sorted by 't_sum'
Grand Totals: Time 1.14k s, Lock 78 s, Rows sent 13.53k, Rows Examined 122.80M


______________________________________________________________________ 001 ___
Count         : 1.44k  (16.46%)
Time          : 958 s total, 667.131 ms avg, 0 to 3 s max  (83.81%)
  95% of Time : 872 s total, 639.296 ms avg, 0 to 1 s max
Lock Time (s) : 18 s total, 12.535 ms avg, 0 to 1 s max  (23.08%)
  95% of Lock : 0 total, 0 avg, 0 to 0 max
Rows sent     : 0 avg, 0 to 0 max  (0.00%)
Rows examined : 0 avg, 0 to 0 max  (0.00%)
Database      : ent
Users         :
        portail@chapu.mondomaine.fr 10.5.1.12 : 34.33% (493) of query, 33.71% (2941) of all users
        portail@chapi.mondomaine.fr 10.5.1.3 : 33.29% (478) of query, 32.88% (2869) of all users
        portail@chapo.mondomaine.fr 10.5.1.6 : 32.38% (465) of query, 31.75% (2770) of all users

Query abstract:
UPDATE up_ss_user_parm SET param_val='S' WHERE user_id=N AND profile_id=N AND ss_id=N AND ss_type=N AND param_name='S';

Query sample: 
UPDATE UP_SS_USER_PARM SET PARAM_VAL='layout' WHERE USER_ID=1905 AND PROFILE_ID=1 AND SS_ID=3 AND SS_TYPE=1 AND PARAM_NAME='current_structure';

______________________________________________________________________ 002 ___
Count         : 1.43k  (16.40%)
Time          : 92 s total, 64.291 ms avg, 0 to 2 s max  (8.05%)
  95% of Time : 17 s total, 12.509 ms avg, 0 to 1 s max
Lock Time (s) : 53 s total, 37.037 ms avg, 0 to 2 s max  (67.95%)
  95% of Lock : 0 total, 0 avg, 0 to 0 max
Rows sent     : 1 avg, 1 to 1 max  (10.58%)
Rows examined : 33.79k avg, 33.79k to 33.79k max  (39.37%)
Database      : ent
Users         :
        portail@chapu.mondomaine.fr 10.5.1.12 : 34.45% (493) of query, 33.71% (2941) of all users
        portail@chapi.mondomaine.fr 10.5.1.3 : 33.47% (479) of query, 32.88% (2869) of all users
        portail@chapo.mondomaine.fr 10.5.1.6 : 32.08% (459) of query, 31.75% (2770) of all users

Query abstract:
SELECT param_val FROM up_ss_user_parm WHERE user_id=N AND profile_id=N AND ss_id=N AND ss_type=N AND param_name='S';
 
Query sample: 
SELECT PARAM_VAL FROM UP_SS_USER_PARM WHERE USER_ID=1905 AND PROFILE_ID=1 AND SS_ID=3 AND SS_TYPE=1 AND PARAM_NAME='current_structure';

______________________________________________________________________ 003 ___
Count         : 62  (0.71%)
Time          : 41 s total, 661.29 ms avg, 0 to 1 s max  (3.59%)
  95% of Time : 37 s total, 637.931 ms avg, 0 to 1 s max
Lock Time (s) : 0 total, 0 avg, 0 to 0 max  (0.00%)
  95% of Lock : 0 total, 0 avg, 0 to 0 max
Rows sent     : 1 avg, 1 to 1 max  (0.46%)
Rows examined : 642.59k avg, 642.59k to 642.59k max  (32.44%)
Database      : syslog
Users         :
        nagios2@monitor2.mondomaine.fr 10.4.1.24 : 66.13% (41) of query, 0.47% (41) of all users
        nagios@monitor.mondomaine.fr 10.4.1.10 : 33.87% (21) of query, 0.24% (21) of all users

Query abstract:
SELECT COUNT(*) FROM logs WHERE msg='S';

Query sample:
select count(*) from `logs` where `msg`='check_logserver: Nagios Log Server UDP Check 1235539516.74';

______________________________________________________________________ 004 ___
[...]

Les solutions

En synthèse les solutions sont assez peu nombreuses:

  • concernant les problèmes de configuration du service MySQL, il faut s'assurer que les paramètres du service sont bien en adéquation avec les paramètres du "serveur physique" (mémoire, temps d'accès disque, etc) et avec les contraintes imposées par d'autres services tournant sur le même serveur physique.
  • concernant les problèmes de conception de base, il vaut mieux en général déléguer le travail aux concepteurs, l'idée étant d'éviter des requêtes algorithmiquement très lourdes (cf exemple des jointures cité plus haut), d'accélérer la recherche des données par la création et l'utilisation de vues, et de créer des index pour toutes les tables sur lesquelles les mêmes requêtes sont exécutées de façon récurrente.

Pour les administrateurs n'étant pas très à l'aise avec la manipulation de MySQL en CLI, il est possible d'effectuer toutes les opérations d'optimisation de bases grâce à des interfaces graphiques:

  • applis web comme phpmyadmin (l'inconvénient est alors lié aux failles de sécurité de l'outil),
  • client lourd comme HeidiSQL (l'inconvénient est alors d'ouvrir le service sur l'interface publique du serveur).

Dans des cas extrèmes où la base est trop grosse pour être gérée par 1 seul serveur, il est possible d'améliorer le service en mettant plusieurs MySQL en cluster. Le gain est alors un gain de performance et de fiabilité (meilleure résistance aux pannes).

Liens utiles

Documentation officielle MySQL 5.1 sur le loggage des Slow Queries

Guide d'isolation des Slow Queries pour les newbies, en Anglais

Guide d'interprétation du rapport MySQL, en Anglais

Lien vers l'utilitaire MySQL mysqlsla, non fournit par défaut

HeidiSQL Homepage