Подтвердить что ты не робот

PHP system() с использованием MySQL для запуска запросов во многих базах данных

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

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

У меня есть сервер базы данных облаков 4gb, работающий под 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 script.

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 мб

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

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

Ответ 3

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

$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 был в стороне.

Ответ 4

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

Я столкнулся с аналогичной проблемой с PTHREADS под PHP7 (и 512Go ОЗУ), которая обрабатывала 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 асинхронных вставок max, в зависимости от вашей глобальной длины вставки.

Ответ 5

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

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

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

Ответ 6

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

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

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

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

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

Ответ 7

Обновлено:

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

Поскольку у вас нет доступа к серверу 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 script? попробуйте создать или сгенерировать через php оболочку script. затем запустите оболочку script.

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

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

Затем выполните php или оболочку script.

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

Сообщите мне, нужно ли мне что-то разъяснять.