Самый безопасный способ выполнить mysqldump на работающей системе с активными операциями чтения и записи?

79

Я не уверен, что это правда, но я помню чтение, если вы запустите следующую команду в Linux

mysqldump -u username -p database_name > backup_db.sql

в то время как операции чтения и записи выполняются в базе данных, дамп может содержать ошибки.

Есть ли в команде определенные параметры, mysqldumpчтобы убедиться, что это сделано безопасно в работающей системе? Я в порядке, что чтение / запись отключены для наших пользователей на несколько секунд (база данных <50 МБ)

user784637
источник

Ответы:

84

Все данные InnoDB

Вот что даст вам точный моментальный снимок данных:

mysqldump -uuser -ppass --single-transaction --routines --triggers --all-databases > backup_db.sql

--single-transactionсоздает контрольную точку, которая позволяет дампу захватывать все данные до контрольной точки при получении входящих изменений. Эти входящие изменения не становятся частью дампа. Это обеспечивает одинаковый момент времени для всех таблиц.

--routines выводит все хранимые процедуры и хранимые функции

--triggers сбрасывает все триггеры для каждой таблицы, в которой они есть

Все данные являются MyISAM или смесью InnoDB / MyISAM

Вам придется наложить глобальную блокировку чтения, выполнить mysqldump и снять глобальную блокировку

mysql -uuser -ppass -Ae"FLUSH TABLES WITH READ LOCK; SELECT SLEEP(86400)" &
sleep 5
mysql -uuser -ppass -ANe"SHOW PROCESSLIST" | grep "SELECT SLEEP(86400)" > /tmp/proclist.txt
SLEEP_ID=`cat /tmp/proclist.txt | awk '{print $1}'`
echo "KILL ${SLEEP_ID};" > /tmp/kill_sleep.sql
mysqldump -uuser -ppass --single-transaction --routines --triggers --all-databases > backup_db.sql
mysql -uuser -ppass -A < /tmp/kill_sleep.sql

Попробуйте!

ОБНОВЛЕНИЕ 2012-06-22 08:12 ПО ВОСТОЧНОМУ ВРЕМЕНИ

Поскольку у вас есть <50 МБ общих данных, у меня есть еще один вариант. Вместо того, чтобы запускать команду SLEEP в фоновом режиме, чтобы удерживать глобальную блокировку чтения в течение 86400 секунд (то есть 24 часа) только для того, чтобы получить идентификатор процесса и уничтожить его снаружи, давайте попробуем установить 5-секундный тайм-аут в mysql, а не в ОС:

SLEEP_TIMEOUT=5
SQLSTMT="FLUSH TABLES WITH READ LOCK; SELECT SLEEP(${SLEEP_TIMEOUT})"
mysql -uuser -ppass -Ae"${SQLSTMT}" &
mysqldump -uuser -ppass --single-transaction --routines --triggers --all-databases > backup_db.sql

Это более чистый и простой подход для очень маленьких баз данных.

RolandoMySQLDBA
источник
1
5 секунд это просто предосторожность. Вы можете попробовать более низкие значения.
RolandoMySQLDBA
1
Роландо - ERROR 2013 (HY000) at line 1: Lost connection to MySQL server during queryэто ожидаемое сообщение об ошибке?
user784637
1
Все ли данные MySQL вышли в mysqldump?
RolandoMySQLDBA
1
Я не уверен насчет сообщения об ошибке. Это только предположение, но это могло произойти из однострочного скрипта, который убивает вызов пользовательской функции SLEEP, о котором я упоминал во втором скрипте.
RolandoMySQLDBA
1
Попробуйте мое новое предложение и посмотрите, будет ли оно хорошо. Надеюсь, сообщения об ошибке не будет.
RolandoMySQLDBA
1

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

Талик Айхингер
источник
1

Вот как я это сделал. Он должен работать во всех случаях, поскольку он использует FLUSH TABLES WITH READ LOCK.

#!/bin/bash

DB=example
DUMP_FILE=export.sql

# Lock the database and sleep in background task
mysql -uroot -proot $DB -e "FLUSH TABLES WITH READ LOCK; DO SLEEP(3600);" &
sleep 3

# Export the database while it is locked
mysqldump -uroot -proot --opt $DB > $DUMP_FILE

# When finished, kill the previous background task to unlock
kill $! 2>/dev/null
wait $! 2>/dev/null

echo "Finished export, and unlocked !"

Команда shell sleepпредназначена только для того, чтобы убедиться, что фоновая задача, выполняющая команду блокировки mysql, выполняется до запуска mysqldump. Вы можете уменьшить его до 1 секунды, и все равно должно быть в порядке. Увеличьте его до 30 секунд и попробуйте вставить значения в любую таблицу из другого клиента в течение этих 30 секунд, которые вы увидите, что он заблокирован.

Есть 2 преимущества в использовании этой ручной блокировки фона вместо использования mysqldumpопций --single-transactionи --lock-tables:

  1. Это блокирует все, если вы смешали таблицы MyISAM / InnoDB.
  2. Вы можете выполнять другие команды в дополнение к mysqldumpтому же периоду блокировки. Это полезно, например, при настройке репликации на главном узле, потому что вам нужно получить позицию двоичного журнала с SHOW MASTER STATUS;точным состоянием созданного вами дампа (до разблокировки базы данных), чтобы иметь возможность создать ведомое устройство репликации.
Nicomak
источник
1

Предложение официальной документации тузд является то , что вы должны иметь мастер базы данных «M1» и ведомого «S1» базы данных , которая описана в разделе «Сценарий 2: Резервное копирование с только для чтения Раба» Резервное копирование ведущего или ведомого устройства, делая его Только чтение

Вы должны установить подчиненную базу данных только для чтения и выполнить

Виктор Гюго Аранго А.
источник
0

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

#!/bin/sh

my_user="user"
my_password="password"
my_db="vpn"
my_table="traffic"
my_step=100000

read -p "Dumping table ${my_db}.${my_table} to ${my_table}.sql?" yn
case $yn in
    [Yy]* ) break;;
    * ) echo "User cancel."; exit;;
esac

my_count=$(mysql $my_db -u $my_user -p$my_password -se "SELECT count(*) FROM $my_table")
my_count=$(($my_count + 0))

if [ ! $my_count ]
then
    echo "No records found"
    exit
fi

echo "Records in table ${my_db}.${my_table}: ${my_count}"

echo "" > $my_table.sql

max_progress=60

for (( limit=0; limit<=$my_count; limit+=$my_step )); do
    progress=$((max_progress * ( limit + my_step) / my_count))

    echo -ne "Dumping ["
    for ((i=0; i<$progress; i ++)); do
        echo -ne "#"
    done
    for ((; i<$max_progress; i ++)); do
        echo -ne "."
    done

    mysqldump -u $my_user -p$my_password --complete-insert --no-create-info --opt --where="1 limit $limit , $my_step" $my_db $my_table >> $my_table.sql
    echo "" >> $my_table.sql

    echo -ne "] $((100 * ( limit + my_step ) / my_count)) %"
    echo -ne "\r"

    sleep 1

done

echo -ne "\n"
vadim_hr
источник