Lorsque le serveur MySQL manquait d'espace disque, l'une des erreurs suivantes s'affichait dans votre application (ainsi que dans le journal des erreurs MySQL) :
ERROR 3 (HY000) at line 1: Error writing file '/tmp/AY0Wn7vA' (Errcode: 28 - No space left on device)
Pour le journal binaire, le message d'erreur ressemble à ceci :
[ERROR] [MY-000035] [Server] Disk is full writing './binlog.000019' (OS errno 28 - No space left on device). Waiting for someone to free space... Retry in 60 secs. Message reprinted in 600 secs.
Pour le journal de relais, le message d'erreur ressemble à ceci :
[ERROR] [MY-000035] [Server] Disk is full writing './relay-bin.000007' (OS errno 28 - No space left on device). Waiting for someone to free space... Retry in 60 secs. Message reprinted in 600 secs.
Pour un journal de requêtes lent, vous verriez un message d'erreur comme celui-ci :
[ERROR] [MY-011263] [Server] Could not use /var/log/mysql/mysql-slow.log for logging (error 28 - No space left on device). Turning logging off for the server process. To turn it on again: fix the cause, then either restart the query logging by using "SET GLOBAL SLOW_QUERY_LOG=ON" or restart the MySQL server.
Pour InnoDB, cela ressemble à ceci :
[ERROR] [MY-012144] [InnoDB] posix_fallocate(): Failed to preallocate data for file ./#innodb_temp/temp_8.ibt, desired size 16384 bytes. Operating system error number 28. Check that the disk is not full or a disk quota exceeded. Make sure the file system supports this function. Some operating system error numbers are described at http://dev.mysql.com/doc/refman/8.0/en/operating-system-error-codes.html
[Warning] [MY-012638] [InnoDB] Retry attempts for writing partial data failed.
[ERROR] [MY-012639] [InnoDB] Write to file ./#innodb_temp/temp_8.ibt failed at offset 81920, 16384 bytes should have been written, only 0 were written. Operating system error number 28. Check that your OS and file system support files of this size. Check also that the disk is not full or a disk quota exceeded.
[ERROR] [MY-012640] [InnoDB] Error number 28 means 'No space left on device'
[Warning] [MY-012145] [InnoDB] Error while writing 16384 zeroes to ./#
Ils signalent tous le même numéro de code d'erreur qui est 28. Alternativement, nous pouvons utiliser le code d'erreur pour voir l'erreur réelle avec la commande perror :
$ perror 28
OS error code 28: No space left on device
Ce qui précède signifie simplement que le serveur MySQL manque d'espace disque et que, la plupart du temps, MySQL est arrêté ou bloqué à ce stade. Dans cet article de blog, nous allons examiner les moyens de résoudre ce problème pour MySQL exécuté dans un environnement Linux.
Dépannage
Tout d'abord, nous devons déterminer quelle partition de disque est pleine. MySQL peut être configuré pour stocker des données sur un disque ou une partition différente. Regardez le chemin comme indiqué dans l'erreur pour commencer. Dans cet exemple, notre répertoire est situé à l'emplacement par défaut, /var/lib/mysql qui se trouve sous la partition /. Nous pouvons utiliser la commande df et spécifier le chemin complet vers le datadir pour obtenir la partition où les données sont stockées :
$ df -h /var/lib/mysql
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 40G 40G 20K 100% /
Ce qui précède signifie que nous devons libérer de l'espace dans la partition racine.
Solutions de contournement temporaires
La solution de contournement temporaire consiste à libérer de l'espace disque afin que MySQL puisse écrire sur le disque et reprendre l'opération. Les choses que nous pouvons faire si nous rencontrons ce type de problème sont liées à :
- La suppression des fichiers inutiles
- Purge des logs binaires
- Supprimer d'anciennes tables ou reconstruire une très grande table
Supprimer les fichiers inutiles
C'est généralement la première étape à faire si le serveur MySQL est en panne ou ne répond pas, ou si vous n'avez pas de journaux binaires activés. Par exemple, les fichiers sous /var/log/ sont généralement le premier endroit où rechercher les fichiers inutiles :
$ cd /var/log
$ find . -type f -size +5M -exec du -sh {} +
8.1M ./audit/audit.log.6
8.1M ./audit/audit.log.5
8.1M ./audit/audit.log.4
8.1M ./audit/audit.log.3
8.1M ./audit/audit.log.2
8.1M ./audit/audit.log.1
11M ./audit/audit.log
8.5M ./secure-20190429
8.0M ./wtmp
L'exemple ci-dessus montre comment récupérer des fichiers de plus de 5 Mo. Nous pouvons supprimer en toute sécurité les fichiers journaux pivotés qui sont généralement au format {filename}.{number}, par exemple de audit.log.1 à audit.log.6. La même chose peut être dite à propos de toutes les énormes sauvegardes plus anciennes qui sont stockées sur le serveur. Si vous avez effectué une restauration via Percona Xtrabackup ou MariaDB Backup, tous les fichiers préfixés par xtrabackup_ peuvent être supprimés du répertoire de données MySQL, car ils ne sont plus nécessaires à la restauration. Le xtrabackup_logfile est généralement le fichier le plus volumineux car il contient toutes les transactions exécutées pendant que le processus xtrabackup copie le datadir vers la destination. L'exemple suivant montre tous les fichiers associés dans MySQL datadir :
$ ls -lah /var/lib/mysql | grep xtrabackup_
-rw-r-----. 1 mysql root 286 Feb 4 11:30 xtrabackup_binlog_info
-rw-r--r--. 1 mysql root 24 Feb 4 11:31 xtrabackup_binlog_pos_innodb
-rw-r-----. 1 mysql root 83 Feb 4 11:31 xtrabackup_checkpoints
-rw-r-----. 1 mysql root 808 Feb 4 11:30 xtrabackup_info
-rw-r-----. 1 mysql root 179M Feb 4 11:31 xtrabackup_logfile
-rw-r--r--. 1 mysql root 1 Feb 4 11:31 xtrabackup_master_key_id
-rw-r-----. 1 mysql root 248 Feb 4 11:31 xtrabackup_tablespaces
Par conséquent, les fichiers mentionnés peuvent être supprimés en toute sécurité. Démarrez le service MySQL une fois qu'il y a au moins 10 % d'espace libre en plus.
Purger les journaux binaires
Si le serveur MySQL est toujours réactif et que le journal binaire est activé, par exemple, pour la réplication ou la récupération ponctuelle, nous pouvons purger les anciens fichiers journaux binaires en utilisant l'instruction PURGE et en fournissant le intervalle. Dans cet exemple, nous supprimons tous les journaux binaires d'avant 3 jours :
mysql> SHOW BINARY LOGS;
mysql> PURGE BINARY LOGS BEFORE DATE(NOW() - INTERVAL 3 DAY);
mysql> SHOW BINARY LOGS;
Pour la réplication MySQL, vous pouvez supprimer en toute sécurité tous les journaux qui ont été répliqués et appliqués sur les esclaves. Vérifiez la valeur Relay_Master_Log_File sur le serveur :
mysql> SHOW SLAVE STATUS\G
...
Relay_Master_Log_File: binlog.000008
...
Et supprimez les anciens fichiers journaux, par exemple binlog.000007 et plus anciens. Il est recommandé de redémarrer le serveur MySQL pour s'assurer qu'il dispose de suffisamment de ressources. Nous pouvons également laisser la rotation des journaux binaires se produire automatiquement via la variable expire_logs_days (
Ensuite, ajoutez la ligne suivante dans le fichier de configuration MySQL sous la section [mysqld] :
Dans MySQL 8.0, utilisez plutôt binlog_expire_logs_seconds, où la valeur par défaut est 2592000 secondes (30 jours). Dans cet exemple, nous le réduisons à seulement 3 jours (60 secondes x 60 minutes x 24 heures x 3 jours) :
SET PERSIST s'assurera que la configuration est chargée au prochain redémarrage. La configuration définie par cette commande est stockée dans /var/lib/mysql/mysqld-auto.cnf. Notez que l'opération DELETE ne libérera pas d'espace disque à moins que OPTIMIZE TABLE ne soit exécuté par la suite. Ainsi, si vous avez supprimé de nombreuses lignes et que vous souhaitez restituer l'espace libre au système d'exploitation après une énorme opération DELETE, exécutez OPTIMIZE TABLE ou reconstruisez-le. Par exemple :
Nous pouvons également forcer la reconstruction d'une table en utilisant l'instruction ALTER :
Notez que l'opération DDL ci-dessus est effectuée via DDL en ligne, ce qui signifie que MySQL autorise les opérations DML simultanées pendant la reconstruction. Une autre façon d'effectuer une opération de défragmentation consiste à utiliser mysqldump pour vider la table dans un fichier texte, supprimer la table et la recharger à partir du fichier de vidage. En fin de compte, nous pouvons également utiliser DROP TABLE pour supprimer la table inutilisée ou TRUNCATE TABLE pour effacer toutes les lignes de la table, ce qui rend par conséquent l'espace au système d'exploitation. La solution permanente est bien sûr d'ajouter plus d'espace au disque ou à la partition correspondante, ou d'appliquer une règle de rétention plus courte pour conserver les fichiers inutiles sur le serveur. Si vous utilisez un système de stockage de fichiers évolutif, vous devriez pouvoir augmenter la ressource sans trop de tracas, ou avec un minimum d'interruptions et de temps d'arrêt du service MySQL. Pour en savoir plus sur la façon de dimensionner votre stockage et comprendre la planification de la capacité MySQL et MariaDB, consultez cet article de blog.
Les problèmes de base de données liés au disque sont l'un des problèmes les plus courants concernant les administrateurs de base de données MySQL et les développeurs travaillant avec le SGBDR - cependant, bien que ces problèmes puissent être répandus, il existe également de nombreuses façons de les résoudre - et de les résoudre pour de bon. Les moyens de résoudre un tel problème ne sont pas toujours simples, mais ils peuvent tous être résolus avec un peu d'effort et d'assistance fournis par des outils tels que ClusterControl.
Grâce aux capacités de surveillance proactive de ClusterControl, les problèmes liés à la base de données devraient être le cadet de vos soucis :vous recevrez une notification sous la forme d'un avertissement lorsque l'espace disque a atteint 80 %, et une notification sous la forme d'un avertissement critique si votre l'utilisation du disque atteint 90 % ou plus. Nous espérons que cet article de blog vous a permis de résoudre au moins quelques problèmes liés à l'utilisation de l'espace disque MySQL, profitez de votre utilisation de ClusterControl et nous vous verrons dans le prochain blog.mysql> SET GLOBAL expire_logs_days = 3;
expire_logs_days=3
mysql> SET GLOBAL binlog_expire_logs_seconds = (60*60*24*3);
mysql> SET PERSIST binlog_expire_logs_seconds = (60*60*24*3);
Supprimer les anciennes tables/reconstruire les tables
mysql> DELETE tbl_name WHERE id < 100000; -- remove 100K rows
mysql> OPTIMIZE TABLE tbl_name;
mysql> ALTER TABLE tbl_name FORCE;
mysql> ALTER TABLE tbl_name; -- a.k.a "null" rebuild
Solutions permanentes aux problèmes d'espace disque
Résumé