Когато на сървъра на MySQL свърши дисково пространство, ще видите една от следните грешки във вашето приложение (както и в регистъра за грешки на MySQL):
ERROR 3 (HY000) at line 1: Error writing file '/tmp/AY0Wn7vA' (Errcode: 28 - No space left on device)
За двоичен дневник съобщението за грешка изглежда така:
[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.
За регистъра на релето съобщението за грешка изглежда така:
[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.
За бавен журнал на заявки ще видите съобщение за грешка, както следва:
[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.
За InnoDB изглежда така:
[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 ./#
Всички те отчитат един и същ код за грешка, който е 28. Като алтернатива можем да използваме кода за грешка, за да видим действителната грешка с командата perror:
$ perror 28
OS error code 28: No space left on device
Горното просто означава, че MySQL сървърът е без дисково пространство и през повечето време MySQL е спрян или спрян в този момент. В тази публикация в блога ще разгледаме начини за решаване на този проблем за MySQL, работещ в Linux-базирана среда.
Отстраняване на неизправности
Първо трябва да определим кой дисков дял е пълен. MySQL може да бъде конфигуриран да съхранява данни на различен диск или дял. Вижте пътя, както е посочено в грешката, за да започнете. В този пример нашата директория се намира в местоположението по подразбиране, /var/lib/mysql, което е под / дяла. Можем да използваме командата df и да посочим пълния път към datadir, за да получим дяла, в който данните се съхраняват:
$ df -h /var/lib/mysql
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 40G 40G 20K 100% /
Горното означава, че трябва да изчистим малко място в основния дял.
Временни решения
Временното решение е да се освободи малко дисково пространство, така че MySQL да може да записва на диска и да възобнови операцията. Нещата, които можем да направим, ако се сблъскаме с подобен проблем са свързани с:
- Премахването на ненужни файлове
- Изчистване на двоичните регистрационни файлове
- Изхвърляне на стари таблици или възстановяване на много голяма маса
Премахване на ненужните файлове
Обикновено това е първата стъпка, която трябва да направите, ако MySQL сървърът не работи или не реагира или нямате активирани двоични регистрационни файлове. Например файловете под /var/log/ обикновено са първото място за търсене на ненужни файлове:
$ 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
Горният пример показва как да извличате файлове, които са по-големи от 5MB. Можем безопасно да премахнем завъртените регистрационни файлове, които обикновено са във формат {filename}.{number}, например от audit.log.1 до audit.log.6. Същото може да се каже за всички огромни по-стари архиви, които се съхраняват на сървъра. Ако сте извършили възстановяване чрез Percona Xtrabackup или MariaDB Backup, всички файлове с префикс xtrabackup_ могат да бъдат премахнати от MySQL datadir, тъй като вече не са необходими за възстановяването. xtrabackup_logfile обикновено е най-големият файл, тъй като съдържа всички транзакции, изпълнени, докато процесът на xtrabackup копира datadir до местоназначението. Следният пример показва всички свързани файлове в 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
Следователно, споменатите файлове са безопасни за изтриване. Стартирайте услугата MySQL, след като има поне 10% повече свободно място.
Изчистете двоичните регистрационни файлове
Ако сървърът на MySQL все още реагира и има активиран двоичен регистрационен файл, например за репликация или възстановяване в даден момент, можем да изчистим старите двоични регистрационни файлове, като използваме израза PURGE и предоставяме интервал. В този пример изтриваме всички двоични регистрационни файлове преди 3 дни:
mysql> SHOW BINARY LOGS;
mysql> PURGE BINARY LOGS BEFORE DATE(NOW() - INTERVAL 3 DAY);
mysql> SHOW BINARY LOGS;
За MySQL репликация е безопасно да изтриете всички регистрационни файлове, които са били репликирани и приложени към подчинени. Проверете стойността Relay_Master_Log_File на сървъра:
mysql> SHOW SLAVE STATUS\G
...
Relay_Master_Log_File: binlog.000008
...
И изтрийте по-старите регистрационни файлове, например binlog.000007 и по-стари. Добра практика е да рестартирате MySQL сървъра, за да сте сигурни, че има достатъчно ресурси. Можем също така да оставим ротацията на двоичния журнал да се случва автоматично чрез променливата expire_logs_days (
След това добавете следния ред в конфигурационния файл на MySQL под секцията [mysqld]:
В MySQL 8.0 вместо това използвайте binlog_expire_logs_seconds, където стойността по подразбиране е 2592000 секунди (30 дни). В този пример го намаляваме до само 3 дни (60 секунди x 60 минути x 24 часа x 3 дни):
SET PERSIST ще гарантира, че конфигурацията е заредена при следващото рестартиране. Конфигурацията, зададена от тази команда, се съхранява в /var/lib/mysql/mysqld-auto.cnf. Обърнете внимание, че операцията DELETE няма да освободи дисково пространство, освен ако OPTIMIZE TABLE не се изпълни след това. По този начин, ако сте изтрили много редове и искате да върнете свободното пространство обратно в операционната система след огромна операция DELETE, стартирайте OPTIMIZE TABLE или я създайте отново. Например:
Можем също да принудим да изградим отново таблица, като използваме оператор ALTER:
Имайте предвид, че горната DDL операция се извършва чрез онлайн DDL, което означава, че MySQL позволява едновременни DML операции, докато възстановяването е в ход. Друг начин за извършване на операция по дефрагментиране е да използвате mysqldump, за да изхвърлите таблицата в текстов файл, да пуснете таблицата и да я презаредите от дъмп файла. В крайна сметка можем също да използваме DROP TABLE, за да премахнем неизползваната таблица, или TRUNCATE TABLE, за да изчистим всички редове в таблицата, което следователно връща пространството обратно в ОС. Постоянното решение, разбира се, е добавяне на повече пространство към съответния диск или дял или прилагане на по-кратко правило за задържане, за да запазите ненужните файлове в сървъра. Ако работите върху мащабируема система за съхранение на файлове, трябва да можете да увеличите ресурса без прекалено много караница или с минимално прекъсване и прекъсване на услугата MySQL. За да научите повече за това как да оразмерите вашето хранилище и да разберете планирането на капацитета на MySQL и MariaDB, вижте тази публикация в блога.
Проблемите с базата данни, свързани с диска, са един от най-разпространените проблеми, засягащи администраторите на бази данни на MySQL и разработчиците, работещи с RDBMS - но въпреки че тези проблеми може да са преобладаващи, има и много начини за решаването им - и за разрешаването им завинаги. Начините за справяне с подобен проблем може да не са винаги ясни, но всички те могат да бъдат решени с малко усилия и помощ, предоставена от инструменти като ClusterControl.
С възможностите за проактивно наблюдение на ClusterControl проблемите, свързани с базата данни, трябва да са най-малкото от притесненията ви:ще получите известие под формата на предупреждение, когато дисковото пространство достигне 80%, и известие под формата на критично предупреждение, ако използването на диска достига 90% или повече. Надяваме се, че тази публикация в блога ви е позволила да разрешите поне няколко от проблемите, свързани с използването на MySQL дисково пространство, да се насладите на използването на ClusterControl и ще се видим в следващия блог.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);
Изхвърлете старите таблици / Възстановете таблици
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
Постоянни решения на проблеми с дисковото пространство
Резюме