Gdy serwerowi MySQL zabraknie miejsca na dysku, zobaczysz jeden z następujących błędów w swojej aplikacji (jak również w dzienniku błędów MySQL):
ERROR 3 (HY000) at line 1: Error writing file '/tmp/AY0Wn7vA' (Errcode: 28 - No space left on device)
W przypadku dziennika binarnego komunikat o błędzie wygląda tak:
[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.
W przypadku dziennika przekaźnika komunikat o błędzie wygląda tak:
[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.
W przypadku powolnego dziennika zapytań zobaczysz komunikat o błędzie, taki jak:
[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.
W przypadku InnoDB wygląda to tak:
[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 ./#
Wszystkie zgłaszają ten sam kod błędu, który wynosi 28. Alternatywnie możemy użyć kodu błędu, aby zobaczyć rzeczywisty błąd za pomocą polecenia perror:
$ perror 28
OS error code 28: No space left on device
Powyższe oznacza po prostu, że serwer MySQL nie ma miejsca na dysku i przez większość czasu MySQL jest w tym momencie zatrzymany lub zablokowany. W tym poście na blogu przyjrzymy się sposobom rozwiązania tego problemu dla MySQL działającego w środowisku opartym na Linuksie.
Rozwiązywanie problemów
Przede wszystkim musimy określić, która partycja dysku jest pełna. MySQL można skonfigurować do przechowywania danych na innym dysku lub partycji. Na początek spójrz na ścieżkę podaną w błędzie. W tym przykładzie nasz katalog znajduje się w domyślnej lokalizacji /var/lib/mysql, która znajduje się pod partycją /. Możemy użyć polecenia df i określić pełną ścieżkę do katalogu danych, aby uzyskać partycję, na której przechowywane są dane:
$ df -h /var/lib/mysql
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 40G 40G 20K 100% /
Powyższe oznacza, że musimy zwolnić trochę miejsca na partycji głównej.
Tymczasowe obejścia
Tymczasowe obejście polega na wyczyszczeniu części miejsca na dysku, aby MySQL mógł zapisywać na dysku i wznowić operację. Rzeczy, które możemy zrobić, jeśli napotkamy tego rodzaju problem, są związane z:
- Usuwanie niepotrzebnych plików
- Czyszczenie dzienników binarnych
- Upuszczanie starych stołów lub odbudowywanie bardzo dużego stołu
Usuń niepotrzebne pliki
Jest to zwykle pierwszy krok, który należy wykonać, jeśli serwer MySQL nie działa lub nie odpowiada, albo nie masz włączonych dzienników binarnych. Na przykład pliki w katalogu /var/log/ są zwykle pierwszym miejscem wyszukiwania niepotrzebnych plików:
$ 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
Powyższy przykład pokazuje, jak odzyskać pliki większe niż 5 MB. Możemy bezpiecznie usunąć rotowane pliki dziennika, które zwykle są w formacie {nazwa pliku}.{numer}, na przykład od audit.log.1 do audit.log.6. To samo można powiedzieć o wszelkich dużych starszych kopiach zapasowych przechowywanych na serwerze. Jeśli przywracanie odbywało się za pomocą Percona Xtrabackup lub MariaDB Backup, wszystkie pliki z prefiksem xtrabackup_ można usunąć z katalogu danych MySQL, ponieważ nie są już potrzebne do przywrócenia. Plik xtrabackup_logfile jest zwykle największym plikiem, ponieważ zawiera wszystkie transakcje wykonane podczas procesu xtrabackup kopiowania katalogu datadir do miejsca docelowego. Poniższy przykład pokazuje wszystkie powiązane pliki w katalogu danych MySQL:
$ 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
Dlatego wspomniane pliki są bezpieczne do usunięcia. Uruchom usługę MySQL, gdy będzie co najmniej 10% więcej wolnego miejsca.
Wyczyść dzienniki binarne
Jeśli serwer MySQL nadal odpowiada i ma włączony dziennik binarny, np. do celów replikacji lub odzyskiwania do określonego momentu, możemy wyczyścić stare pliki dziennika binarnego, używając instrukcji PURGE i podając interwał. W tym przykładzie usuwamy wszystkie logi binarne sprzed 3 dni:
mysql> SHOW BINARY LOGS;
mysql> PURGE BINARY LOGS BEFORE DATE(NOW() - INTERVAL 3 DAY);
mysql> SHOW BINARY LOGS;
W przypadku replikacji MySQL można bezpiecznie usunąć wszystkie dzienniki, które zostały zreplikowane i zastosowane na urządzeniach podrzędnych. Sprawdź wartość Relay_Master_Log_File na serwerze:
mysql> SHOW SLAVE STATUS\G
...
Relay_Master_Log_File: binlog.000008
...
I usuń starsze pliki dziennika, na przykład binlog.000007 i starsze. Dobrą praktyką jest ponowne uruchomienie serwera MySQL, aby upewnić się, że ma wystarczającą ilość zasobów. Możemy również pozwolić, aby rotacja logów binarnych odbywała się automatycznie za pomocą zmiennej execute_logs_days (
Następnie dodaj następujący wiersz do pliku konfiguracyjnego MySQL w sekcji [mysqld]:
W MySQL 8.0 użyj zamiast tego binlog_expire_logs_seconds, gdzie domyślna wartość to 2592000 sekund (30 dni). W tym przykładzie skróciliśmy go do zaledwie 3 dni (60 sekund x 60 minut x 24 godziny x 3 dni):
SET PERSIST upewni się, że konfiguracja zostanie załadowana przy następnym restarcie. Konfiguracja ustawiona przez to polecenie jest przechowywana w /var/lib/mysql/mysqld-auto.cnf. Pamiętaj, że operacja DELETE nie zwolni miejsca na dysku, chyba że później zostanie wykonane polecenie OPTIMIZE TABLE. Tak więc, jeśli usunąłeś wiele wierszy i chciałbyś zwrócić wolne miejsce z powrotem do systemu operacyjnego po ogromnej operacji DELETE, uruchom OPTIMIZE TABLE lub odbuduj ją. Na przykład:
Możemy również wymusić przebudowanie tabeli za pomocą instrukcji ALTER:
Należy zauważyć, że powyższa operacja DDL jest wykonywana za pośrednictwem DDL online, co oznacza, że MySQL zezwala na współbieżne operacje DML podczas trwającej odbudowy. Innym sposobem wykonania operacji defragmentacji jest użycie mysqldump do zrzucenia tabeli do pliku tekstowego, upuszczenia tabeli i ponownego załadowania jej z pliku zrzutu. Ostatecznie możemy również użyć DROP TABLE, aby usunąć nieużywaną tabelę lub TRUNCATE TABLE, aby wyczyścić wszystkie wiersze w tabeli, co w konsekwencji zwróci przestrzeń z powrotem do systemu operacyjnego. Stałym rozwiązaniem jest oczywiście dodanie większej ilości miejsca do odpowiedniego dysku lub partycji lub zastosowanie krótszej reguły przechowywania, aby zachować niepotrzebne pliki na serwerze. Jeśli korzystasz ze skalowalnego systemu przechowywania plików, powinieneś być w stanie skalować zasób w górę bez większych kłopotów lub przy minimalnych zakłóceniach i przestojach usługi MySQL. Aby dowiedzieć się więcej o tym, jak wymiarować pamięć masową i zrozumieć planowanie pojemności MySQL i MariaDB, zapoznaj się z tym wpisem na blogu.
Problemy z bazą danych związane z dyskami są jednym z najczęstszych problemów dotyczących administratorów baz danych MySQL i programistów pracujących z RDBMS – jednak, chociaż te problemy mogą być powszechne, istnieje również wiele sposobów ich rozwiązania – i rozwiązania ich na dobre. Sposoby rozwiązania tego problemu nie zawsze są proste, jednak wszystkie można rozwiązać przy odrobinie wysiłku i pomocy zapewnianej przez narzędzia takie jak ClusterControl.
Dzięki możliwościom proaktywnego monitorowania ClusterControl, problemy związane z bazą danych powinny być najmniejszym zmartwieniem:otrzymasz powiadomienie w formie ostrzeżenia, gdy miejsce na dysku osiągnie 80%, oraz powiadomienie w formie ostrzeżenia krytycznego, jeśli wykorzystanie dysku osiąga 90% lub więcej. Mamy nadzieję, że ten wpis na blogu pozwolił rozwiązać przynajmniej kilka problemów związanych z wykorzystaniem miejsca na dysku MySQL, cieszyć się korzystaniem z ClusterControl i do zobaczenia w następnym blogu.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);
Upuść stare tabele / Przebuduj tabele
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
Stałe rozwiązania problemów z miejscem na dysku
Podsumowanie