Når MySQL-serveren løb tør for diskplads, ville du se en af følgende fejl i din applikation (såvel som i MySQL-fejlloggen):
ERROR 3 (HY000) at line 1: Error writing file '/tmp/AY0Wn7vA' (Errcode: 28 - No space left on device)
For binær log ser fejlmeddelelsen sådan ud:
[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.
For relælog ser fejlmeddelelsen sådan ud:
[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.
For langsom forespørgselslog vil du se en fejlmeddelelse som sådan:
[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.
For InnoDB ser det sådan ud:
[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 ./#
De rapporterer alle det samme fejlkodenummer, som er 28. Alternativt kan vi bruge fejlkoden til at se den faktiske fejl med perror-kommandoen:
$ perror 28
OS error code 28: No space left on device
Ovenstående betyder simpelthen, at MySQL-serveren er løbet tør for diskplads, og det meste af tiden er MySQL stoppet eller stoppet på dette tidspunkt. I dette blogindlæg skal vi se på måder at løse dette problem for MySQL, der kører i et Linux-baseret miljø.
Fejlfinding
Først og fremmest skal vi bestemme, hvilken diskpartition der er fuld. MySQL kan konfigureres til at gemme data på en anden disk eller partition. Se på stien som angivet i fejlen til at starte med. I dette eksempel er vores bibliotek placeret på standardplaceringen, /var/lib/mysql, som er under partitionen /. Vi kan bruge kommandoen df og angive den fulde sti til datadirigenten for at få den partition, dataene er gemt:
$ df -h /var/lib/mysql
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 40G 40G 20K 100% /
Ovenstående betyder, at vi skal rydde lidt plads i rodpartitionen.
Midlertidige løsninger
Den midlertidige løsning er at rydde op på diskplads, så MySQL kan skrive til disken og genoptage handlingen. Ting, vi kan gøre, hvis vi står over for denne type problemer er relateret til:
- Fjernelse af unødvendige filer
- Sletning af de binære logfiler
- Slipning af gamle borde eller genopbygning af et meget stort bord
Fjern unødvendige filer
Dette er normalt det første trin, du skal gøre, hvis MySQL-serveren er nede eller ikke reagerer, eller du ikke har aktiveret binære logfiler. For eksempel er filer under /var/log/ almindeligvis det første sted at lede efter unødvendige filer:
$ 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
Ovenstående eksempel viser, hvordan man henter filer, der er større end 5MB. Vi kan sikkert fjerne de roterede logfiler, som normalt er i formatet {filename}.{number}, for eksempel fra audit.log.1 til audit.log.6. Det samme kan siges om alle store ældre sikkerhedskopier, der er gemt på serveren. Hvis du havde udført en gendannelse via Percona Xtrabackup eller MariaDB Backup, kan alle filer med præfiks med xtrabackup_ fjernes fra MySQL datadir, da de ikke længere er nødvendige for gendannelsen. xtrabackup_logfilen er normalt den største fil, da den indeholder alle transaktioner, der udføres, mens xtrabackup-processen kopierer datafilen til destinationen. Følgende eksempel viser alle de relaterede filer i 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
Derfor er de nævnte filer sikre at blive slettet. Start MySQL-tjenesten, når der er mindst 10 % mere ledig plads.
Tøm de binære logfiler
Hvis MySQL-serveren stadig reagerer, og den har binær log aktiveret, f.eks. til replikering eller punkt-i-tidsgendannelse, kan vi rense de gamle binære logfiler ved at bruge PURGE-sætningen og levere interval. I dette eksempel sletter vi alle binære logfiler før 3 dage siden:
mysql> SHOW BINARY LOGS;
mysql> PURGE BINARY LOGS BEFORE DATE(NOW() - INTERVAL 3 DAY);
mysql> SHOW BINARY LOGS;
For MySQL-replikering er det sikkert at slette alle logfiler, der er blevet replikeret og anvendt på slaver. Tjek værdien Relay_Master_Log_File på serveren:
mysql> SHOW SLAVE STATUS\G
...
Relay_Master_Log_File: binlog.000008
...
Og slet de ældre logfiler, f.eks. binlog.000007 og ældre. Det er god praksis at genstarte MySQL-serveren for at sikre, at den har nok ressourcer. Vi kan også lade den binære log-rotation ske automatisk via variabelen expire_logs_days (
Tilføj derefter følgende linje i MySQL-konfigurationsfilen under [mysqld]-sektionen:
I MySQL 8.0 skal du bruge binlog_expire_logs_seconds i stedet, hvor standardværdien er 2592000 sekunder (30 dage). I dette eksempel reducerer vi det til kun 3 dage (60 sekunder x 60 minutter x 24 timer x 3 dage):
SET PERSIST sørger for, at konfigurationen indlæses ved næste genstart. Konfiguration indstillet af denne kommando er gemt i /var/lib/mysql/mysqld-auto.cnf. Bemærk, at DELETE handlingen ikke frigør diskplads, medmindre OPTIMIZE TABLE udføres efterfølgende. Således, hvis du har slettet mange rækker, og du gerne vil returnere den ledige plads tilbage til OS efter en enorm DELETE-operation, skal du køre OPTIMER-TABELLEN eller genopbygge den. For eksempel:
Vi kan også tvinge til at genopbygge en tabel ved at bruge ALTER-sætning:
Bemærk, at ovenstående DDL-operation udføres via online DDL, hvilket betyder, at MySQL tillader samtidige DML-operationer, mens genopbygningen er i gang. En anden måde at udføre en defragmenteringsoperation på er at bruge mysqldump til at dumpe tabellen til en tekstfil, slippe tabellen og genindlæse den fra dumpfilen. I sidste ende kan vi også bruge DROP TABLE til at fjerne den ubrugte tabel eller TRUNCATE TABLE for at rydde op i alle rækker i tabellen, som følgelig returnerer pladsen tilbage til OS. Den permanente løsning er naturligvis at tilføje mere plads til den tilsvarende disk eller partition, eller at anvende en kortere opbevaringsregel for at beholde unødvendige filer på serveren. Hvis du kører oven på et skalerbart fillagringssystem, bør du være i stand til at skalere ressourcen op uden for meget besvær eller med minimal afbrydelse og nedetid til MySQL-tjenesten. For at lære mere om, hvordan du dimensionerer dit lager og forstår MySQL- og MariaDB-kapacitetsplanlægning, så tjek dette blogindlæg.
Diskrelaterede databaseproblemer er et af de mest udbredte problemer vedrørende MySQL-databaseadministratorer og -udviklere, der arbejder med RDBMS ens - men selvom disse problemer kan være fremherskende, er der også mange måder at løse dem på - og løse dem for altid. Måden at tackle et sådant problem på er måske ikke altid ligetil, men de kan alle løses med en lille smule indsats og hjælp fra værktøjer som ClusterControl.
Med ClusterControls proaktive overvågningsmuligheder bør databaserelaterede problemer være de mindste af dine bekymringer:Du vil få en meddelelse i form af en advarsel, når diskpladsen har nået 80 %, og en meddelelse i form af en kritisk advarsel, hvis din diskbrug når 90 % eller mere. Vi håber, at dette blogindlæg har givet dig mulighed for at løse i det mindste et par af problemerne relateret til MySQL-diskpladsbrug, nyd din brug af ClusterControl, og vi ses i den næste 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);
Drop gamle tabeller / Genopbyg tabeller
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
Permanente løsninger på problemer med diskplads
Oversigt