Найбезпечніший спосіб виконати mysqldump в живій системі з активними читаннями і записами?


78

Я не впевнений, чи це правда, але я пам’ятаю, що читав, якщо ви виконаєте наступну команду в Linux

mysqldump -u username -p database_name > backup_db.sql

в той час як читання і запис робиться в базі даних, то дамп може містити помилки.

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

Відповіді:


82

Усі дані є 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 EDT

Оскільки у вас є <50MB загальних даних, у мене є ще один варіант. Замість того, щоб запускати команду 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

Це більш чистий і простий підхід для дуже малих баз даних.


1
5 секунд - це просто обережність. Можна спробувати менші значення.
RolandoMySQLDBA

1
Роландо - це ERROR 2013 (HY000) at line 1: Lost connection to MySQL server during queryочікуване повідомлення про помилку?
користувач784637

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 !"

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

Є два переваги використання цього ручного блокування фону, а не використання mysqldumpпараметрів --single-transactionта --lock-tables:

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

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"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.