Najbezpieczniejszy sposób wykonywania mysqldump w systemie na żywo z aktywnymi odczytami i zapisami?

78

Nie jestem pewien, czy to prawda, ale pamiętam czytanie, jeśli uruchomisz następującą komendę w systemie Linux

mysqldump -u username -p database_name > backup_db.sql

podczas odczytywania i zapisywania w bazie danych zrzut może zawierać błędy.

Czy w poleceniu są określone opcje, mysqldumpaby upewnić się, że odbywa się to bezpiecznie w systemie na żywo? Nie mam nic przeciwko wyłączeniu odczytu / zapisu dla naszych użytkowników na kilka sekund (baza danych <50 MB)

użytkownik784637
źródło

Odpowiedzi:

82

Wszystkie dane to InnoDB

Oto, co da ci dokładną migawkę danych w czasie:

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

--single-transactiontworzy punkt kontrolny, który pozwala zrzutowi przechwycić wszystkie dane przed punktem kontrolnym podczas odbierania nadchodzących zmian. Te nadchodzące zmiany nie stają się częścią zrzutu. Zapewnia to taki sam moment dla wszystkich tabel.

--routines zrzuca wszystkie procedury przechowywane i funkcje przechowywane

--triggers zrzuca wszystkie wyzwalacze dla każdej tabeli, która je ma

Wszystkie dane to MyISAM lub Mix InnoDB / MyISAM

Będziesz musiał nałożyć globalną blokadę odczytu, wykonać mysqldump i zwolnić globalną blokadę

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

Spróbuj !!!

AKTUALIZACJA 22.06.2012 08:12 EDT

Ponieważ masz mniej niż 50 MB danych, mam inną opcję. Zamiast uruchamiać komendę SLEEP w tle, aby zablokować globalną blokadę odczytu przez 86400 sekund (24 godziny) tylko po to, aby uzyskać identyfikator procesu i zabić na zewnątrz, spróbujmy ustawić 5-sekundowy limit czasu w mysql zamiast w systemie operacyjnym:

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

Jest to czystsze i prostsze podejście do bardzo małych baz danych.

RolandoMySQLDBA
źródło
1
5 sekund to tylko środek ostrożności. Możesz wypróbować niższe wartości.
RolandoMySQLDBA
1
Rolando - czy ERROR 2013 (HY000) at line 1: Lost connection to MySQL server during queryoczekiwany jest komunikat o błędzie?
user784637
1
Czy wszystkie dane MySQL pojawiły się w mysqldump?
RolandoMySQLDBA
1
Nie jestem pewien co do komunikatu o błędzie. To tylko przypuszczenie, ale mogło pochodzić ze skryptu jednowierszowego, który zabija zdefiniowane przez użytkownika wywołanie funkcji SLEEP, o którym wspomniałem w drugim skrypcie.
RolandoMySQLDBA
1
Wypróbuj moją nową sugestię i sprawdź, czy pójdzie dobrze. Mamy nadzieję, że nie pojawi się komunikat o błędzie.
RolandoMySQLDBA
2
  • W przypadku tabel InnoDB należy użyć --single-transactionopcji, jak wspomniano w innej odpowiedzi.
  • Dla MyISAM jest --lock-tables.

Zobacz oficjalną dokumentację tutaj

pesco
źródło
1

Jeśli chcesz to zrobić dla MyISAM lub tabel mieszanych bez żadnych przestojów w blokowaniu tabel, możesz skonfigurować podrzędną bazę danych i zabrać stamtąd migawki. Ustawienie bazy danych podrzędnych niestety powoduje eksport przestarzałej bazy danych przez pewien czas przestoju, ale po jej uruchomieniu powinieneś być w stanie zablokować jej tabele i eksportować przy użyciu metod opisanych przez innych. Gdy tak się dzieje, opóźnia się w stosunku do wzorca, ale nie powstrzymuje wzorca przed aktualizacją swoich tabel i nadrabia zaległości po zakończeniu tworzenia kopii zapasowej.

Talik Eichinger
źródło
1

Oto jak to zrobiłem. Powinien działać we wszystkich przypadkach, ponieważ używa 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 !"

Polecenie powłoki sleepsłuży tylko do upewnienia się, że zadanie w tle uruchamiające polecenie blokujące mysql jest wykonywane przed uruchomieniem mysqldump. Możesz go skrócić do 1 sekundy i nadal powinno być dobrze. Zwiększ go do 30 sekund i spróbuj wstawić wartości do dowolnej tabeli innego klienta w ciągu tych 30 sekund, kiedy zobaczysz, że jest zablokowana.

Korzystanie z ręcznego blokowania tła ma dwie zalety, zamiast korzystania z mysqldumpopcji --single-transactioni --lock-tables:

  1. To blokuje wszystko, jeśli masz mieszane tabele MyISAM / InnoDB.
  2. Możesz wykonywać inne polecenia oprócz tego mysqldumpw tym samym okresie blokowania. Jest to przydatne na przykład podczas konfigurowania replikacji w węźle głównym, ponieważ musisz uzyskać pozycję dziennika binarnego z SHOW MASTER STATUS;dokładnym stanem utworzonego zrzutu (przed odblokowaniem bazy danych), aby móc utworzyć podrzędną replikację.
Nicomak
źródło
0

jeśli masz bardzo dużą tabelę MYISAM i musisz ją zrzucić bez blokady i uniknąć dużego obciążenia serwera, możesz użyć następującego skryptu.

#!/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
źródło