Wenn der Speicherplatz des MySQL-Servers erschöpft war, wurde in Ihrer Anwendung (sowie im MySQL-Fehlerprotokoll) einer der folgenden Fehler angezeigt:
ERROR 3 (HY000) at line 1: Error writing file '/tmp/AY0Wn7vA' (Errcode: 28 - No space left on device)
Für das Binärlog sieht die Fehlermeldung so aus:
[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.
Für das Relay-Log sieht die Fehlermeldung so aus:
[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.
Bei einem langsamen Abfrageprotokoll würden Sie eine Fehlermeldung wie diese sehen:
[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.
Für InnoDB sieht es so aus:
[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 ./#
Sie alle melden dieselbe Fehlercodenummer, nämlich 28. Alternativ können wir den Fehlercode verwenden, um den tatsächlichen Fehler mit dem perror-Befehl anzuzeigen:
$ perror 28
OS error code 28: No space left on device
Das Obige bedeutet einfach, dass der MySQL-Server keinen Speicherplatz mehr hat und MySQL an dieser Stelle die meiste Zeit angehalten oder blockiert wird. In diesem Blogpost werden wir nach Möglichkeiten suchen, dieses Problem für MySQL zu lösen, das in einer Linux-basierten Umgebung ausgeführt wird.
Fehlerbehebung
Zunächst müssen wir feststellen, welche Festplattenpartition voll ist. MySQL kann so konfiguriert werden, dass Daten auf einer anderen Festplatte oder Partition gespeichert werden. Sehen Sie sich zunächst den Pfad an, der in der Fehlermeldung angegeben ist. In diesem Beispiel befindet sich unser Verzeichnis am Standardspeicherort /var/lib/mysql, der sich unter der Partition / befindet. Wir können den df-Befehl verwenden und den vollständigen Pfad zum Datenverzeichnis angeben, um die Partition zu erhalten, in der die Daten gespeichert sind:
$ df -h /var/lib/mysql
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 40G 40G 20K 100% /
Das Obige bedeutet, dass wir etwas Platz in der Root-Partition schaffen müssen.
Vorübergehende Problemumgehungen
Die vorübergehende Problemumgehung besteht darin, Speicherplatz freizugeben, damit MySQL auf die Festplatte schreiben und den Vorgang fortsetzen kann. Dinge, die wir tun können, wenn wir mit dieser Art von Problem konfrontiert sind, beziehen sich auf:
- Das Entfernen nicht benötigter Dateien
- Bereinigen der Binärlogs
- Alte Tabellen löschen oder eine sehr große Tabelle neu erstellen
Unnötige Dateien entfernen
Dies ist normalerweise der erste Schritt, wenn der MySQL-Server ausgefallen ist oder nicht reagiert oder Sie keine Binärprotokolle aktiviert haben. Beispielsweise sind Dateien unter /var/log/ normalerweise der erste Ort, an dem nach unnötigen Dateien gesucht wird:
$ 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
Das obige Beispiel zeigt, wie Dateien abgerufen werden, die größer als 5 MB sind. Wir können die rotierten Protokolldateien, die normalerweise im Format {Dateiname}.{Nummer} vorliegen, sicher entfernen, beispielsweise von audit.log.1 bis audit.log.6. Dasselbe gilt für große ältere Backups, die auf dem Server gespeichert sind. Wenn Sie eine Wiederherstellung über Percona Xtrabackup oder MariaDB Backup durchgeführt haben, können alle Dateien mit dem Präfix xtrabackup_ aus dem MySQL-Datenverzeichnis entfernt werden, da sie für die Wiederherstellung nicht mehr benötigt werden. Die xtrabackup_logfile ist normalerweise die größte Datei, da sie alle Transaktionen enthält, die ausgeführt werden, während der xtrabackup-Prozess das Datenverzeichnis zum Ziel kopiert. Das folgende Beispiel zeigt alle zugehörigen Dateien im MySQL-Datenverzeichnis:
$ 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
Daher können die genannten Dateien sicher gelöscht werden. Starten Sie den MySQL-Dienst, sobald mindestens 10 % mehr freier Speicherplatz vorhanden sind.
Lösche die Binärprotokolle
Wenn der MySQL-Server immer noch reaktionsfähig ist und das Binärprotokoll aktiviert ist, z. B. für die Replikation oder Wiederherstellung zu einem bestimmten Zeitpunkt, können wir die alten Binärprotokolldateien löschen, indem wir die PURGE-Anweisung verwenden und die Intervall. In diesem Beispiel löschen wir alle Binärlogs vor 3 Tagen:
mysql> SHOW BINARY LOGS;
mysql> PURGE BINARY LOGS BEFORE DATE(NOW() - INTERVAL 3 DAY);
mysql> SHOW BINARY LOGS;
Für die MySQL-Replikation ist es sicher, alle Protokolle zu löschen, die repliziert und auf Slaves angewendet wurden. Überprüfen Sie den Wert von Relay_Master_Log_File auf dem Server:
mysql> SHOW SLAVE STATUS\G
...
Relay_Master_Log_File: binlog.000008
...
Und löschen Sie die älteren Protokolldateien, zum Beispiel binlog.000007 und älter. Es empfiehlt sich, den MySQL-Server neu zu starten, um sicherzustellen, dass er über genügend Ressourcen verfügt. Wir können die Rotation der Binärlogs auch automatisch über die Variable expire_logs_days (
Fügen Sie dann die folgende Zeile in die MySQL-Konfigurationsdatei im Abschnitt [mysqld] ein:
Verwenden Sie in MySQL 8.0 stattdessen binlog_expire_logs_seconds, wobei der Standardwert 2592000 Sekunden (30 Tage) beträgt. In diesem Beispiel reduzieren wir es auf nur 3 Tage (60 Sekunden x 60 Minuten x 24 Stunden x 3 Tage):
SET PERSIST stellt sicher, dass die Konfiguration beim nächsten Neustart geladen wird. Die durch diesen Befehl festgelegte Konfiguration wird in /var/lib/mysql/mysqld-auto.cnf gespeichert. Beachten Sie, dass der DELETE-Vorgang keinen Speicherplatz freigibt, es sei denn, OPTIMIZE TABLE wird danach ausgeführt. Wenn Sie also viele Zeilen gelöscht haben und den freien Speicherplatz nach einer großen DELETE-Operation wieder an das Betriebssystem zurückgeben möchten, führen Sie OPTIMIZE TABLE aus oder erstellen Sie es neu. Zum Beispiel:
Wir können auch erzwingen, dass eine Tabelle neu erstellt wird, indem wir die ALTER-Anweisung verwenden:
Beachten Sie, dass der obige DDL-Vorgang über Online-DDL ausgeführt wird, was bedeutet, dass MySQL gleichzeitige DML-Vorgänge zulässt, während der Neuaufbau im Gange ist. Eine andere Möglichkeit, eine Defragmentierungsoperation durchzuführen, besteht darin, mysqldump zu verwenden, um die Tabelle in eine Textdatei zu sichern, die Tabelle zu löschen und sie aus der Sicherungsdatei neu zu laden. Letztendlich können wir auch DROP TABLE verwenden, um die ungenutzte Tabelle zu entfernen, oder TRUNCATE TABLE, um alle Zeilen in der Tabelle zu löschen, wodurch der Platz wieder an das Betriebssystem zurückgegeben wird. Die dauerhafte Lösung besteht natürlich darin, der entsprechenden Festplatte oder Partition mehr Speicherplatz hinzuzufügen oder eine kürzere Aufbewahrungsregel anzuwenden, um unnötige Dateien auf dem Server zu behalten. Wenn Sie auf einem skalierbaren Dateispeichersystem arbeiten, sollten Sie in der Lage sein, die Ressource ohne allzu großen Aufwand oder mit minimaler Unterbrechung und Ausfallzeit des MySQL-Dienstes hochzuskalieren. Um mehr darüber zu erfahren, wie Sie Ihren Speicher dimensionieren und die MySQL- und MariaDB-Kapazitätsplanung verstehen, lesen Sie diesen Blogbeitrag.
Festplattenbezogene Datenbankprobleme sind eines der häufigsten Probleme bei MySQL-Datenbankadministratoren und Entwicklern, die gleichermaßen mit dem RDBMS arbeiten – obwohl diese Probleme weit verbreitet sein mögen, gibt es auch viele Möglichkeiten, sie zu lösen – und sie für immer zu lösen. Die Wege zur Bewältigung eines solchen Problems sind möglicherweise nicht immer einfach, können jedoch alle mit ein wenig Aufwand und Unterstützung durch Tools wie ClusterControl gelöst werden.
Mit den proaktiven Überwachungsfunktionen von ClusterControl sollten datenbankbezogene Probleme Ihre geringsten Sorgen sein:Sie erhalten eine Benachrichtigung in Form einer Warnung, wenn der Speicherplatz 80 % erreicht hat, und eine Benachrichtigung in Form einer kritischen Warnung, wenn dies der Fall ist Die Festplattenauslastung erreicht 90 % oder mehr. Wir hoffen, dass Sie mit diesem Blogbeitrag zumindest einige der Probleme im Zusammenhang mit der Verwendung von MySQL-Speicherplatz lösen konnten, viel Spaß bei der Verwendung von ClusterControl und wir sehen uns im nächsten 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);
Alte Tabellen löschen / Tabellen neu erstellen
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
Dauerhafte Lösungen für Speicherplatzprobleme
Zusammenfassung