Sicherste Möglichkeit, mysqldump auf einem Live-System mit aktiven Lese- und Schreibvorgängen auszuführen?


78

Ich bin mir nicht sicher, ob dies zutrifft, aber ich erinnere mich, dass ich gelesen habe, wenn Sie den folgenden Befehl unter Linux ausführen

mysqldump -u username -p database_name > backup_db.sql

Während Lese- und Schreibvorgänge in einer Datenbank ausgeführt werden, kann der Speicherauszug Fehler enthalten.

Gibt es bestimmte Optionen im Befehl mysqldump, um sicherzustellen, dass dies auf einem Live-System sicher durchgeführt wird? Ich bin damit einverstanden, dass Lese- / Schreibvorgänge für einige Sekunden für unsere Benutzer deaktiviert werden (Die Datenbank <50 MB).

Antworten:


82

Alle Daten sind InnoDB

So erhalten Sie eine genaue Momentaufnahme der Daten:

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

--single-transactionErzeugt einen Checkpoint, der es dem Dump ermöglicht, alle Daten vor dem Checkpoint zu erfassen, während eingehende Änderungen empfangen werden. Diese eingehenden Änderungen werden nicht Teil des Dumps. Dies stellt für alle Tabellen den gleichen Zeitpunkt sicher.

--routines Sichert alle gespeicherten Prozeduren und gespeicherten Funktionen

--triggers Sichert alle Trigger für jede Tabelle, in der sie enthalten sind

Alle Daten sind MyISAM oder ein Mix aus InnoDB / MyISAM

Sie müssen eine globale Lesesperre festlegen, den mysqldump ausführen und die globale Sperre aufheben

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

Versuche es !!!

UPDATE 2012-06-22 08:12 EDT

Da Sie <50 MB Gesamtdaten haben, habe ich eine andere Option. Anstatt einen SLEEP-Befehl im Hintergrund zu starten, um die globale Lesesperre für 86400 Sekunden (diese 24 Stunden) zu halten, nur um die Prozess-ID abzurufen und außerhalb zu beenden, sollten Sie in mysql statt im Betriebssystem eine Zeitüberschreitung von 5 Sekunden festlegen:

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

Dies ist ein sauberer und einfacherer Ansatz für sehr kleine Datenbanken.


1
5 Sekunden ist nur vorsichtshalber. Sie können niedrigere Werte versuchen.
RolandoMySQLDBA

1
Rolando - wird ERROR 2013 (HY000) at line 1: Lost connection to MySQL server during queryeine Fehlermeldung erwartet?
user784637

1
Sind alle MySQL-Daten im mysqldump herausgekommen?
RolandoMySQLDBA

1
Ich bin mir bei der Fehlermeldung nicht sicher. Dies ist nur eine Vermutung, die möglicherweise von dem einzeiligen Skript stammt, das den benutzerdefinierten SLEEP-Funktionsaufruf beendet, den ich im zweiten Skript erwähnt habe.
RolandoMySQLDBA

1
Versuchen Sie meinen neuen Vorschlag und sehen Sie, ob es gut geht. Hoffentlich gibt es keine Fehlermeldung.
RolandoMySQLDBA

2
  • Für InnoDB-Tabellen sollten Sie die --single-transactionOption verwenden, wie in einer anderen Antwort erwähnt.
  • Für MyISAM gibt es --lock-tables.

Hier finden Sie die offizielle Dokumentation


1

Wenn Sie dies für MyISAM oder gemischte Tabellen ohne Ausfallzeit durch Sperren der Tabellen tun möchten, können Sie eine Slave-Datenbank einrichten und Ihre Snapshots von dort erstellen. Das Einrichten der Slave-Datenbank verursacht leider einige Ausfallzeiten, um die Live-Datenbank zu exportieren. Sobald sie ausgeführt wird, sollten Sie in der Lage sein, ihre Tabellen zu sperren und mit den von anderen beschriebenen Methoden zu exportieren. Wenn dies geschieht, bleibt es hinter dem Master zurück, hindert den Master jedoch nicht daran, seine Tabellen zu aktualisieren, und holt auf, sobald die Sicherung abgeschlossen ist.


1

So habe ich es gemacht. Es sollte in allen Fällen funktionieren, da es verwendet 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 !"

Der Shell- sleepBefehl soll nur sicherstellen, dass die Hintergrund-Task, die den mysql-Sperrbefehl ausführt, ausgeführt wird, bevor mysqldump gestartet wird. Sie könnten es auf 1 Sekunde reduzieren und es sollte immer noch in Ordnung sein. Erhöhen Sie den Wert auf 30 Sekunden und versuchen Sie, in den 30 Sekunden, in denen Sie sehen, dass die Tabelle gesperrt ist, Werte aus einem anderen Client in eine Tabelle einzufügen.

Es gibt zwei Vorteile, wenn Sie diese manuelle Hintergrundsperre verwenden, anstatt die mysqldumpOptionen --single-transactionund --lock-tables:

  1. Dies sperrt alles, wenn Sie MyISAM / InnoDB-Tabellen gemischt haben.
  2. Sie können mysqldumpwährend derselben Sperrzeit auch andere Befehle ausführen . Dies ist beispielsweise nützlich, wenn Sie die Replikation auf einem Masterknoten einrichten, da Sie die Position des Binärprotokolls mit SHOW MASTER STATUS;dem genauen Status des von Ihnen erstellten Speicherauszugs (vor dem Entsperren der Datenbank) abrufen müssen, um einen Replikationsslave erstellen zu können.


0

Wenn Sie eine sehr große MYISAM-Tabelle haben und die Tabelle ohne Sperre sichern und eine hohe Serverauslastung vermeiden müssen, können Sie das folgende Skript verwenden.

#!/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"
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.