У меня есть сценарий ниже, который просматривает 380 баз данных MySQL innodb и запускает различные таблицы создания, вставки, обновления ... и т.д. для переноса схемы. Он запускается с веб-сервера, который подключается к серверу облачной базы данных. Я не затрагиваю этот вопрос о сценарии миграции, поскольку не считаю его актуальным.

У меня возникла проблема, и я пытаюсь найти решение.

У меня есть сервер облачной базы данных 4 ГБ оперативной памяти с MySQL 5.6. Я перенес 380 баз данных с 40 таблицами в 59 таблиц. Примерно 70% пути я получил ошибки ниже. Он умер во время одной миграции, и сервер вышел из строя. Я наблюдал за использованием памяти, и у меня закончилась память. Это база данных как услуга, поэтому у меня нет корневого доступа к серверу, поэтому я не знаю всех деталей.

Выполнение запросов на phppoint_smg


Warning: Using a password on the command line interface can be insecure.
ERROR 2013 (HY000) at line 355: Lost connection to MySQL server during query

Выполнение запросов на phppoint_soulofhalloween


Warning: Using a password on the command line interface can be insecure.
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 0

Выполнение запросов на phppoint_srvais


Warning: Using a password on the command line interface can be insecure.
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 0

Вот упрощенная версия скрипта PHP.

db_host = escapeshellarg($db_host);
$db_user = escapeshellarg($db_user);
$db_password = escapeshellarg($db_password);
foreach($databases as $database)
{
    echo "Running queries on $database\n***********************************\n";
    system("mysql --host=$db_host --user=$db_user --password=$db_password --port=3306 $database < ../update.sql"); 
    echo "\n\n";
}

Мои вопросы:

Есть ли способ избежать увеличения использования памяти при миграции? Я делаю это по одной базе данных за раз. Или добавление таблиц и данных является причиной его роста?

Я смог использовать послесловия сервера, удалил 80 баз данных и завершил миграцию. Имеет 800 мб бесплатно; и я ожидаю, что он упадет до 600 МБ. До миграции было 500мб

13
Chris Muench 6 Май 2016 в 10:16

7 ответов

Лучший ответ

Ваш образец PHP не использует много памяти, и он не работает на сервере базы данных, который вышел из строя, верно? Итак, проблема в ваших настроенных параметрах MySQL.

На основе вашего Gist и с помощью простого Калькулятор памяти MySQL, мы видим, что ваша служба MySQL может использовать до 3817 МБ памяти. Если на момент возникновения ошибки на сервере было только 4 ГБ, вполне вероятно, что это была причина (вам потребуется дополнительная память для ОС и запущенных приложений). Это решило бы увеличение памяти или точная настройка сервера. Взгляните на страницу документации MySQL по серверным переменным, чтобы лучше понять каждое значение.

Однако это может быть не единственной причиной отключений / таймаутов (но, похоже, это ваш случай, поскольку увеличение памяти решило проблему). Другой распространенной проблемой является недооценка значения max_allowed_packet (16 МБ в вашей конфигурации), потому что такие сценарии могут легко иметь запросы, превышающие это значение (например, если у вас есть несколько значений для одного INSERT INTO table ...).

Учтите, что max_allowed_packet должен быть больше, чем самая большая команда, которую вы вводите для своей базы данных (это не файл SQL, а каждая команда в нем, блок между ;).

Но, пожалуйста, подумайте о более тщательной настройке, поскольку неправильно настроенный сервер может внезапно выйти из строя или перестать отвечать на запросы, хотя он может отлично работать без добавления дополнительной памяти. Я предлагаю запустить сценарии настройки производительности, такие как MySQLTuner-perl, которые проанализируют ваши данные, использование индекса, медленные запросы и даже предложат корректировки. вам нужно оптимизировать свой сервер.

2
Capilé 14 Май 2016 в 19:55

Обновлено:

Ваши комментарии полностью меняют ситуацию.
Вот мой обновленный ответ:

Поскольку у вас нет доступа к серверу MySQL, вам нужно использовать альтернативный подход.

Обязательно удалите все специальные "вещи" из файла импорта, такие как включающие транзакции, вставьте отложенные / игнорируемые и т. д.

Обязательно для SQL с одним оператором - Я не знаю, как выглядят вставки, но сделайте это одним оператором - одной вставкой - не объединяйте много строк в один оператор,

Например

Вместо того

insert into x
             (...fields...)values(...single row...),
             (...fields...)values(...single row...), 
             (...fields...)values(...single row...), 
             (...fields...)values(...single row...)
;

Делать

insert into x(...fields...)values(...single row...); 
insert into x(...fields...)values(...single row...); 
insert into x(...fields...)values(...single row...); 
insert into x(...fields...)values(...single row...); 

Тогда попробуйте это:

  • Вы можете попробовать "загрузить" my.ini с большими буферами и так далее. В этом случае поставщик сервера MySQL может предоставить вам больше оперативной памяти. В конце концов, это сервис :)

  • Вы можете попытаться создать файл со схемой и файлы с данными. Затем импортируйте схему, затем начали импортировать таблицу за таблицей и посмотреть, где она вылетает, и возобновить сбой файла.

  • Вы можете импортировать все с помощью таблиц MyISAM. Затем вы можете преобразовать их в InnoDB. alter table x engine=innodb. Однако при этом будет потеряна вся ссылочная целостность, и вам нужно будет применить ее позже.

  • Вы можете импортировать все с помощью таблиц MyISAM. Затем вместо их преобразования вы можете сделать

Примерно так для каждой таблицы:

alter table x rename to x_myisam;
create table x(...);
insert into x select * from x_myisam;

Я считаю, что есть одна таблица, которая мешает процессу. Если вы его найдете, вы можете продолжить вручную. Например, импортируйте 10000 строк за раз или что-то в этом роде.

Альтернативный подход

Если ваш сервер находится в Amazon AWS или аналогичном сервисе, вы можете попробовать «масштабировать» («увеличить») сервер для импорта и «уменьшить» («сжать») после завершения импорта.

Старый ответ

почему вы используете скрипт php? попробуйте создать или сгенерировать через php сценарий оболочки. затем запустите сценарий оболочки.

также очень важно создать в системе огромный файл подкачки. вот один из способов сделать это. Это может не работать в старых системах:

sudo su # became root
cd /somewhere
fallocate -l 16gb file001
mkswap file001
chmod 0 file001
swapon file001

Затем выполните сценарий php или оболочки.

Как только это будет сделано, вы можете поменять местами и удалить файл или сделать его постоянным в fstab.

Дайте мне знать, если мне нужно что-то уточнить.

-2
Nick 10 Май 2016 в 07:08

Я думаю, что они правы насчет барана, но стоит отметить, что инструменты, которые вы используете, важны.

Вы пробовали http://www.mysqldumper.net/? если вы его используете (скрипт php), проверьте настройки ограничения памяти php и дайте ему автоматически определить.

Раньше я использовал http://www.ozerov.de/bigdump/ но это так медленно, что я больше не умею.

Mysqldumper, с другой стороны, быстро выполняет резервное копирование и восстановление, не дает сбоев (если вы установите ограничение памяти)

Я нашел этот инструмент исключительным.

1
iGNEOS 15 Май 2016 в 03:07

Если ваш сервер базы данных дает сбой (или его убивает oom killer), причина в том, что он настроен на использование большего объема памяти, чем доступно на устройстве.

Вы забыли сообщить нам, какая ОС работает на узлах базы данных.

Если у вас нет root-доступа к серверу, то это вина того, кто его настраивал. Перегрузка памяти должна быть отключено (требуется root-доступ). Такой инструмент, как mysqltuner, покажет вам, сколько памяти СУБД сконфигурировано для использования (требуются права администратора). См. Также эту публикацию percona

1
Community 13 Апр 2017 в 12:13

Одна вещь, которую вы должны попытаться освободить от оперативной памяти, поскольку на вашем сервере явно очень мало ОЗУ, - это принудительно выполнить сборку мусора после отключения больших массивов после завершения цикла.

Я столкнулся с аналогичной проблемой с PTHREADS под PHP7 (и 512 ГБ ОЗУ), который обрабатывал 1024 асинхронных соединения с MariaDB и Postgresql на массивном сервере.

Попробуйте это для каждого цикла.

//first unset main immediately at loop start:
unset($databases[$key]);

// second unset process and purge immediately
unset($database);
gc_collect_cycles();

Кроме того, установите элемент управления для постоянного мониторинга использования ОЗУ под нагрузкой, чтобы узнать, происходит ли это в конкретной базе данных $. В случае, если у вас слишком мало оперативной памяти, установите элемент управления для фрагментации вашей базы данных $ и выполнения нескольких пакетов вставки и сбросьте их по мере их выполнения. Это очистит больше ОЗУ и позволит избежать слишком больших копий массива перед циклом вспомогательной вставки. Это особенно актуально, если вы используете классы с конструкцией. С 4Go я бы предпочел установить партии от 400 до 500 макс. Асинхронных вставок, в зависимости от вашей глобальной длины вставки.

1
cpugourou 8 Май 2016 в 23:57

Вместо того, чтобы запускать множество процессов, сгенерируйте один файл, а затем запустите его. Создайте файл что-то вроде

$out = fopen('tmp_script.sql', 'w');
foreach($databases as $database)
{
    fwrite($out, "USE $database;\n");
    fwrite($out, "source ../update.sql;\n");
}
fclose($out);

Затем вручную или программно выполните

mysql ... < tmp_script.sql

Возможно, будет безопаснее сделать это вручную, чтобы не мешать PHP.

2
Rick James 10 Май 2016 в 01:07

Совершенно очевидно, что ваши SQL-запросы миграции убивают сервер. Кажется, что базе данных просто не хватает свободной оперативной памяти для таких действий. В зависимости от размера базы данных и запросов он наверняка может увеличить использование оперативной памяти. Без знания точных спецификаций сервера, данных в базе данных и запросов, которые вы запускаете, нет точного ответа, который мог бы вам здесь помочь.

2
Brain Foo Long 8 Май 2016 в 23:56