Cara teraman untuk melakukan mysqldump pada sistem live dengan membaca dan menulis aktif?

78

Saya tidak yakin apakah ini benar tetapi saya ingat pernah membaca jika Anda menjalankan perintah berikut di linux

mysqldump -u username -p database_name > backup_db.sql

saat membaca dan menulis sedang dilakukan ke database maka dump tersebut mungkin mengandung kesalahan.

Apakah ada opsi khusus dalam perintah mysqldumpuntuk memastikan ini dilakukan dengan aman pada sistem live? Saya setuju dengan pembacaan / penulisan yang dinonaktifkan untuk pengguna kami selama beberapa detik (Basis data <50MB)

pengguna784637
sumber

Jawaban:

82

Semua Data adalah InnoDB

Inilah yang akan memberi Anda snapshot point-in-time data yang tepat:

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

--single-transactionmenghasilkan pos pemeriksaan yang memungkinkan dump untuk menangkap semua data sebelum pos pemeriksaan saat menerima perubahan yang masuk. Perubahan yang masuk itu tidak menjadi bagian dari dump. Itu memastikan point-in-time yang sama untuk semua tabel.

--routines membuang semua prosedur tersimpan dan fungsi tersimpan

--triggers dump semua pemicu untuk setiap tabel yang memilikinya

Semua Data adalah MyISAM atau Campuran InnoDB / MyISAM

Anda harus memaksakan kunci baca global, melakukan mysqldump, dan melepaskan kunci global

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

Cobalah !!!

UPDATE 2012-06-22 08:12 EDT

Karena Anda memiliki <50MB total data, saya memiliki opsi lain. Alih-alih meluncurkan perintah SLEEP ke latar belakang untuk menahan kunci baca global selama 86400 detik (24 jam) hanya untuk mendapatkan ID proses dan membunuh di luar, mari kita coba menetapkan batas waktu 5 detik di mysql daripada di OS:

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

Ini adalah pendekatan yang lebih bersih dan sederhana untuk database yang sangat kecil.

RolandoMySQLDBA
sumber
1
5 detik hanyalah tindakan pencegahan. Anda dapat mencoba nilai yang lebih rendah.
RolandoMySQLDBA
1
Rolando - apakah ERROR 2013 (HY000) at line 1: Lost connection to MySQL server during queryada pesan kesalahan yang diharapkan?
user784637
1
Apakah semua data MySQL keluar di mysqldump?
RolandoMySQLDBA
1
Saya tidak yakin tentang pesan kesalahan. Ini hanya dugaan, tapi itu mungkin berasal dari skrip satu baris yang membunuh panggilan fungsi SLEEP yang ditentukan pengguna yang saya sebutkan dalam skrip kedua.
RolandoMySQLDBA
1
Coba saran baru saya dan lihat apakah itu berjalan dengan baik. Semoga tidak ada pesan kesalahan.
RolandoMySQLDBA
2
  • Untuk tabel InnoDB, Anda harus menggunakan --single-transactionopsi, sebagaimana disebutkan dalam jawaban lain.
  • Untuk MyISAM ada --lock-tables.

Lihat dokumentasi resmi di sini

pesco
sumber
1

Jika Anda ingin melakukan ini untuk MyISAM atau tabel campuran tanpa downtime dari mengunci tabel, Anda dapat mengatur database slave, dan mengambil foto Anda dari sana. Menyiapkan database slave, sayangnya, menyebabkan beberapa downtime untuk mengekspor database live, tetapi begitu itu berjalan, Anda harus dapat mengunci tabel itu, dan mengekspor menggunakan metode yang telah dijelaskan orang lain. Ketika ini terjadi, itu akan tertinggal di belakang master, tetapi tidak akan menghentikan master dari memperbarui tabel itu, dan akan menyusul segera setelah cadangan selesai.

Talik Eichinger
sumber
1

Begini cara saya melakukannya. Ini harus bekerja dalam semua kasus sejak digunakan 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 !"

sleepPerintah shell hanya untuk memastikan bahwa tugas latar belakang yang menjalankan perintah penguncian mysql dijalankan sebelum mysqldump dimulai. Anda bisa menguranginya menjadi 1 detik dan itu harus tetap baik-baik saja. Naikkan menjadi 30 detik dan coba masukkan nilai dalam tabel apa pun dari klien lain selama 30 detik itu Anda akan melihatnya terkunci.

Ada 2 keuntungan dalam menggunakan penguncian latar belakang manual ini, daripada menggunakan mysqldumpopsi --single-transactiondan --lock-tables:

  1. Ini mengunci segalanya, jika Anda telah mencampur tabel MyISAM / InnoDB.
  2. Anda dapat menjalankan perintah lain selain dari mysqldumppada periode penguncian yang sama. Ini berguna, misalnya, ketika mengatur replikasi pada master node, karena Anda perlu mendapatkan posisi log biner dengan SHOW MASTER STATUS;keadaan yang tepat dari dump yang Anda buat (sebelum membuka kunci basis data), untuk dapat membuat budak replikasi.
Nicomak
sumber
1

Saran dari dokumentasi resmi mysql adalah bahwa Anda harus memiliki database Master "M1" dan Database Slave "S1" yang dijelaskan dalam "Skenario 2: Cadangkan dengan Slave Hanya-Baca" Mencadangkan Master atau Slave dengan Membuatnya Baca Saja

Anda harus mengatur basis data slave hanya baca dan lakukan th

Victor Hugo Arango A.
sumber
0

jika Anda memiliki tabel MYISAM yang sangat besar dan Anda perlu membuang tabel tersebut tanpa mengunci dan menghindari beban server yang tinggi, Anda dapat menggunakan skrip berikut.

#!/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
sumber