Cloud SQL pour MySQL est un service de base de données entièrement géré qui vous aide à configurer, entretenir, gérer et administrer votre base de données MySQL, PostgreSQL ou SQL Server sur Google Cloud Platform. Cloud SQL exécute un grand nombre de bases de données MySQL dans son parc. Il est donc fréquent que certaines instances MySQL consomment beaucoup de mémoire et plantent en raison d'une erreur de mémoire saturée (OOM, Out Of Memory). Cet article vous aidera à résoudre les problèmes de mémoire MySQL.
Une condition de mémoire insuffisante (OOM) se produit lorsqu'un processus tente d'allouer de la mémoire et échoue, car le serveur n'a plus de mémoire disponible. Il en résulte souvent le robot tueur OOM Linux, un processus utilisé par le noyau Linux lorsque le système manque de mémoire critique, qui met fin au processus de base de données.
Un plantage de base de données dû à une condition OOM n'est pas idéal, car le processus de base de données est arrêté à l'aide de la directive SIGKILL, ce qui empêche l'application d'arrêter normalement MySQL. Cela entraîne les problèmes suivants :
MySQL a ajouté une instrumentation de mémoire dans performance_schema à partir de la version 5.7, ce qui permet de mieux comprendre l'allocation de mémoire MySQL. Cet article vous aidera à résoudre les problèmes de mémoire MySQL à l'aide de performance_schema.
Chaque instance Cloud SQL est alimentée par une machine virtuelle (VM) exécutée sur un serveur hôte Google Cloud. Chaque VM exploite le programme de base de données, comme le serveur MySQL et les agents de service qui fournissent des services complémentaires, tels que la journalisation et la surveillance. Cloud SQL réserve une partie de la mémoire pour le système d'exploitation (OS) et les agents de service, et alloue de la mémoire restante aux programmes de base de données tels que mysqld.
Le tableau suivant indique l'allocation de mémoire pour le processus mysqld et la configuration par défaut du pool de mémoire tampon InnoDB pour chaque type de machine.
Type de machine | GIB de RAM de l'instance (octets) | Mémoire mysqld (Go) | Pool de mémoire tampon InnoDB, en Gio (octets) | Pool de mémoire tampon (% de RAM de l'instance) | Pool de mémoire tampon (% de mémoire mysqld) |
db-g1-small | 1.7(1825361101) | 1.11 | 0.625(671088640) | 37 % | 56 % |
db-custom-1-3840 | 3.75(4026531840) | 2,97 | 1.375(1476395008) | 37 % | 46 % |
db-custom-2-7680 | 7.5(8053063680) | 6.72 | 4(4294967296) | 53 % | 60 % |
db-custom-2-13312 | 13(13958643712) | 12 | 9(9663676416) | 69 % | 75 % |
db-custom-4-15360 | 15(16106127360) | 14 | 10.5(11274289152) | 70 % | 76 % |
db-custom-4-26624 | 26(27917287424) | 24 | 19(20401094656) | 73 % | 79 % |
db-custom-8-30720 | 30(32212254720) | 28 | 22(23622320128) | 73 % | 80 % |
db-custom-8-53248 | 52(55834574848) | 48 | 38(40802189312) | 73 % | 79 % |
db-custom-16-61440 | 60(64424509440) | 55 | 44(47244640256) | 73 % | 80 % |
db-custom-16-106496 | 104(111669149696) | 96 | 75(80530636800) | 72 % | 78 % |
db-custom-32-122880 | 120(128849018880) | 110 | 87(93415538688) | 73 % | 79 % |
db-custom-32-212992 | 208(223338299392) | 191 | 150(161061273600) | 72 % | 78 % |
db-custom-64-245760 | 240(257698037760) | 221 | 173(185757335552) | 72 % | 78 % |
db-custom-96-368640 | 360(386547056640) | 331 | 260(279172874240) | 72 % | 79 % |
db-custom-64-425984 | 416(446676598784) | 383 | 300(322122547200) | 72 % | 78 % |
db-custom-96-638976 | 624(670014898176) | 574 | 450(483183820800) | 72 % | 78 % |
Type de machine
GIB de RAM de l'instance (octets)
Mémoire mysqld (Go)
Pool de mémoire tampon InnoDB, en Gio (octets)
Pool de mémoire tampon (% de RAM de l'instance)
Pool de mémoire tampon (% de mémoire mysqld)
db-g1-small
1.7(1825361101)
1.11
0.625(671088640)
37 %
56 %
db-custom-1-3840
3.75(4026531840)
2,97
1.375(1476395008)
37 %
46 %
db-custom-2-7680
7.5(8053063680)
6.72
4(4294967296)
53 %
60 %
db-custom-2-13312
13(13958643712)
12
9(9663676416)
69 %
75 %
db-custom-4-15360
15(16106127360)
14
10.5(11274289152)
70 %
76 %
db-custom-4-26624
26(27917287424)
24
19(20401094656)
73 %
79 %
db-custom-8-30720
30(32212254720)
28
22(23622320128)
73 %
80 %
db-custom-8-53248
52(55834574848)
48
38(40802189312)
73 %
79 %
db-custom-16-61440
60(64424509440)
55
44(47244640256)
73 %
80 %
db-custom-16-106496
104(111669149696)
96
75(80530636800)
72 %
78 %
db-custom-32-122880
120(128849018880)
110
87(93415538688)
73 %
79 %
db-custom-32-212992
208(223338299392)
191
150(161061273600)
72 %
78 %
db-custom-64-245760
240(257698037760)
221
173(185757335552)
72 %
78 %
db-custom-96-368640
360(386547056640)
331
260(279172874240)
72 %
79 %
db-custom-64-425984
416(446676598784)
383
300(322122547200)
72 %
78 %
db-custom-96-638976
624(670014898176)
574
450(483183820800)
72 %
78 %
Pour les instances disposant de 10 Go de RAM ou plus, le processus mysqld est limité à 92 % de la RAM de l'instance, et le pool de tampons InnoDB est configuré entre 75 et 80 % de la mémoire disponible pour le processus mysqld. En plus du pool de mémoire tampon InnoDB, MySQL alloue plusieurs tampons et caches pour améliorer les performances. Veuillez consulter cet article pour en savoir plus sur l'allocation de mémoire dans MySQL.
Lorsque l'utilisation de la mémoire mysqld dépasse la limite configurée du processus mysqld, le robot tueur OOM Linux arrête le processus mysqld, car il s'agit du plus grand consommateur de mémoire de l'instance.
performance_schema est une fonctionnalité MySQL permettant de surveiller l'exécution des serveurs à un niveau inférieur. Cloud SQL pour MySQL permet d'activer performance_schema sur les instances dont la taille de RAM est supérieure ou égale à 3 Go. Elle est activée par défaut dans les instances disposant d'au moins 15 Go de RAM, à partir de la version MySQL 8.0.
Performance_schema est désactivée par défaut pour les versions 5.6 et 5.7 de MySQL. Vous pouvez l'activer à l'aide des options de base de données.
L'activation de performance_schema entraîne une surcharge des performances et des conséquences sur la mémoire. Consultez la section sur le modèle d'allocation de mémoire du schéma de performances pour comprendre son allocation de mémoire.
L'instrumentation de mémoire performance_schema permet de surveiller l'utilisation de la mémoire dans MySQL. Les outils liés à la mémoire ont des noms ayant la forme memory/code_area/instrument_name, où code_area est une valeur telle que sql ou Innodb et instrument_name correspond au détail de l'instrument.
MySQL 5.7 active certains outils liés à la mémoire par défaut, mais pas tous. Vous pouvez les activer en mettant à jour la colonne ENABLED de la table performance_schema.setup_instruments.
mysql> select version();
+-------------------+
| version() |
+-------------------+
| 5.7.39-google-log |
+-------------------+
1 row in set (0.00 sec)
mysql> SELECT enabled, count(*) FROM performance_schema.setup_instruments WHERE NAME LIKE '%memory%' group by enabled;
+---------+----------+
| enabled | count(*) |
+---------+----------+
| YES | 70 |
| NO | 306 |
+---------+----------+
1186 rows in set (0.03 sec)
mysql> UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME LIKE 'memory/%';
Query OK, 306 rows affected (0.00 sec)
Lignes correspondantes : 376 Modifiées : 306 Avertissements : 0
mysql> SELECT enabled, count(*) FROM performance_schema.setup_instruments WHERE NAME LIKE '%memory%' group by enabled;
+---------+----------+
| enabled | count(*) |
+---------+----------+
| YES | 376 |
+---------+----------+
1 row in set (0.00 sec)
L'activation des instruments de mémoire au moment de l'exécution ne comptabilise que les objets mémoire créés après l'activation de l'instrumentation. Il est donc recommandé d'attendre que le serveur collecte suffisamment de données pour résoudre les problèmes.
MySQL 8.0 active tous les instruments de mémoire par défaut.
mysql> select version();
+---------------+
| version() |
+---------------+
| 8.0.28-google |
+---------------+
1 row in set (0.00 sec)
mysql> SELECT enabled, count(*) FROM performance_schema.setup_instruments WHERE NAME LIKE '%memory%' group by enabled;
+---------+----------+
| enabled | count(*) |
+---------+----------+
| YES | 490 |
+---------+----------+
1 row in set (0.00 sec)
Le schéma système contient de nombreuses vues qui résument les données de performance_schema sous des formes facilement compréhensibles. La plupart de ces vues sont présentées par paires. Elles portent le même nom et l'une d'entre elles a le préfixe x$. Les vues suivantes sont disponibles dans MySQL 5.7 et 8.0 pour afficher l'allocation de mémoire à différents niveaux.
mysql> utilise sys;
Base de données modifiée
mysql> afficher des tables telles que '%memory%';
+-------------------------------------+
| Tables_in_sys (%memory%) |
+-------------------------------------+
| memory_by_host_by_current_bytes |
| memory_by_thread_by_current_bytes |
| memory_by_user_by_current_bytes |
| memory_global_by_current_bytes |
| memory_global_total |
| x$memory_by_host_by_current_bytes |
| x$memory_by_thread_by_current_bytes |
| x$memory_by_user_by_current_bytes |
| x$memory_global_by_current_bytes |
| x$memory_global_total |
+-------------------------------------+
10 rows in set (0.02 sec)
La vue sys.memory_global_total résume l'utilisation totale de la mémoire dans un format lisible.
mysql> select * from sys.memory_global_total;
+-----------------+
| total_allocated |
+-----------------+
| 12.43 GiB |
+-----------------+
1 row in set (0.44 sec)
sys.x$memory_global_total affiche les mêmes informations, mais en octets.
mysql> select * from sys.x$memory_global_total;
+-----------------+
| total_allocated |
+-----------------+
| 13351482992 |
+-----------------+
1 row in set (1.39 sec)
La vue sans le préfixe x$ est destinée à fournir une sortie plus conviviale et plus lisible. La vue avec le préfixe x$ qui affiche les mêmes valeurs au format brut est davantage destinée à être utilisée avec d'autres outils qui effectuent leur propre traitement sur les données.
La vue sys.memory_global_by_current_bytes indique l'utilisation actuelle de la mémoire, regroupée par type d'allocation (event_name), par exemple "memory/innodb/buf_buf_pool" (pool de mémoire tampon InnoDB). Par défaut, les lignes sont triées par ordre décroissant de quantité de mémoire utilisée.
Avant d'examiner en détail chaque type d'allocation, il est judicieux d'avoir un aperçu de l'utilisation de la mémoire pour chaque zone de code comme Innodb, sql, performance_schema, etc.
La requête suivante agrège la mémoire actuellement allouée par zone de code.
SELECT SUBSTRING_INDEX(event_name,'/',2) AS code_area,
FORMAT_BYTES(SUM(current_alloc)) AS current_alloc
FROM sys.x$memory_global_by_current_bytes
GROUP BY SUBSTRING_INDEX(event_name,'/',2)
ORDER BY SUM(current_alloc) DESC;
+---------------------------+---------------+
| code_area | current_alloc |
+---------------------------+---------------+
| memory/innodb | 11.28 GiB |
| memory/performance_schema | 520.02 MiB |
| memory/temptable | 514.00 MiB |
| memory/sql | 106.12 MiB |
| memory/mysys | 43.25 MiB |
| memory/vio | 372.15 KiB |
| memory/myisam | 696 bytes |
| memory/csv | 88 bytes |
| memory/blackhole | 88 bytes |
+---------------------------+---------------+
9 rows in set (1.02 sec)
Ce résultat montre qu'innodb est le plus grand consommateur de mémoire, suivi de performance_schema et des tables temporaires.
Désormais, l'interrogation de sys.memory_global_by_current_bytes affiche directement l'utilisation de la mémoire pour les structures internes MySQL, comme décrit dans la colonne event_name. Si vous tentez de résoudre un problème d'augmentation anormale de la mémoire, vous pouvez identifier la source en examinant le résultat de cette vue.
mysql> select event_name,current_alloc,high_alloc from sys.memory_global_by_current_bytes limit 5;
+-------------------------------+---------------+------------+
| event_name | current_alloc | high_alloc |
+-------------------------------+---------------+------------+
| memory/innodb/buf_buf_pool | 10.72 GiB | 10.72 GiB |
| memory/temptable/physical_ram | 514.00 MiB | 515.00 MiB |
| memory/innodb/hash0hash | 292.69 MiB | 292.69 MiB |
| memory/innodb/memory | 191.77 MiB | 197.94 MiB |
| memory/sql/TABLE | 60.39 MiB | 62.35 MiB |
+-------------------------------+---------------+------------+
5 rows in set (0.45 sec)
Vous trouverez ci-dessous des informations détaillées sur chaque type de répartition.
Type d'allocation | Détails |
memory/innodb/buf_buf_pool | Mémoire utilisée par le pool de mémoire tampon InnoDB |
memory/temptable/physical_ram | Mémoire utilisée par les tables temporaires internes |
memory/innodb/hash0hash | Mémoire utilisée par la table de hachage InnoDB |
memory/innodb/memory | Mémoire utilisée par divers tampons InnoDB |
memory/sql/TABLE | Mémoire utilisée par les objets TABLE et leur racine mem |
Type d'allocation
Détails
memory/innodb/buf_buf_pool
Mémoire utilisée par le pool de mémoire tampon InnoDB
memory/temptable/physical_ram
Mémoire utilisée par les tables temporaires internes
memory/innodb/hash0hash
Mémoire utilisée par la table de hachage InnoDB
memory/innodb/memory
Mémoire utilisée par divers tampons InnoDB
memory/sql/TABLE
Mémoire utilisée par les objets TABLE et leur racine mem
Cette vue récapitule l'utilisation de la mémoire regroupée par utilisateur. Si un utilisateur dispose de plusieurs connexions, elle additionne l'utilisation de la mémoire pour toutes les instances de l'utilisateur.
mysql> select user,current_allocated from memory_by_user_by_current_bytes;
+-----------------+-------------------+
| user | current_allocated |
+-----------------+-------------------+
| sbtest | 60.30 MiB |
| background | 2.68 MiB |
| root | 1.52 MiB |
| event_scheduler | 16.38 KiB |
+-----------------+-------------------+
4 rows in set (1.16 sec)
Si vous utilisez un utilisateur différent pour chaque application ou tâche (recommandé), cette vue peut vous aider à déterminer si une application ou une tâche en particulier consomme beaucoup de mémoire.
Cette vue récapitule l'utilisation de mémoire regroupée en fonction du nom d'hôte.
mysql> select host,current_allocated from memory_by_host_by_current_bytes;
+------------+-------------------+
| host | current_allocated |
+------------+-------------------+
| 10.128.0.8 | 62.10 MiB |
| background | 2.70 MiB |
| 127.0.0.1 | 311.01 KiB |
| localhost | 16.38 KiB |
+------------+-------------------+
4 rows in set (1.58 sec)
Cette vue est utile pour identifier l'utilisation de mémoire par hôte client. De nos jours, il est très courant d'avoir plusieurs clients/serveurs d'applications. Cette vue vous aidera à déterminer si un client ou une charge de travail spécifique entraîne une utilisation élevée de la mémoire. Vous pouvez également déployer le changement en premier sur un client/serveur d'applications, surveiller son impact sur la mémoire (en comparant son utilisation à celle d'autres hôtes clients) et prendre des décisions éclairées.
Cette vue récapitule l'utilisation de la mémoire, regroupées par thread. Elle permet de trouver les threads qui occupent le plus de mémoire.
mysql> select thread_id,user,current_allocated from sys.memory_by_thread_by_current_bytes limit 5;
+-----------+-------------------+-------------------+
| thread_id | user | current_allocated |
+-----------+-------------------+-------------------+
| 12999 | sbtest@10.128.0.8 | 3.80 MiB |
| 12888 | sbtest@10.128.0.8 | 3.75 MiB |
| 12760 | sbtest@10.128.0.8 | 3.68 MiB |
| 13128 | sbtest@10.128.0.8 | 3.67 MiB |
| 13221 | sbtest@10.128.0.8 | 3.47 MiB |
+-----------+-------------------+-------------------+
5 rows in set (2.29 sec)
Si vous constatez qu'un thread particulier consomme beaucoup de mémoire, vous pouvez filtrer les journaux des requêtes lentes MySQL ou les journaux généraux à l'aide de thread_id et identifier la ou les sessions/requêtes qui ont entraîné la croissance de la mémoire.
Le dépannage d'une utilisation de mémoire élevée n'est pas une mince affaire. Heureusement, l'instrumentation de mémoire performance_schema aide les utilisateurs à comprendre comment la mémoire est utilisée par les structures MySQL internes. Les vues de schéma système facilitent l'interprétation des informations. Si vous rencontrez des problèmes liés à la mémoire, cette fonctionnalité vous aidera à en trouver la source. Vous pourrez alors y remédier en modifiant la configuration ou la requête.
Exemple :
Imaginons qu'une instance MySQL utilise une quantité de mémoire supérieure à ce qu'elle devrait et que cette utilisation augmente continuellement jusqu'à ce que le serveur soit à court de mémoire. Dans ce cas, le champ performance_schema affiche un écart entre la mémoire totale et la mémoire instrumentée ou ne vous indique pas où va la mémoire, ce qui pourrait être le signe d'une fuite de mémoire. Si vous suspectez une fuite de mémoire, vous pouvez prendre les mesures suivantes :
Profitez de 300 $ de crédits gratuits et de plus de 20 produits Always Free pour commencer à créer des applications sur Google Cloud.