memulihkan satu database mysql pada sistem replikasi master-slave yang sibuk

10

Mencari strategi atau alat untuk menangani memulihkan satu basis data ke titik waktu dalam sistem replikasi yang sibuk.

Saya memiliki 12 database yang berjalan di 2 server MySQL 5.0.77 dalam konfigurasi replikasi master-slave. Sebuah dump penuh diambil dari slave read-only setiap hari, dan ada dump SQL tambahan yang tersedia, dengan cadangan ini di luar situs dan status replikasi dimonitor.

Sunting: Tabel adalah campuran dari InnoDB dan myISAM, karenanya solusi spesifik mesin tidak tersedia.

Jadi, mengingat kegagalan total server master, saya dapat memecahkan replikasi dan mempromosikan server slave, saya juga memiliki opsi untuk membangun kembali server baru dan mengkonfigurasi dari backup FULL offside, dan kemudian menerapkan diferensial yang diambil setiap jam dari slave.

Namun saya khawatir bagaimana menangani kegagalan parsial, atau kegagalan satu database. Saya bisa memikirkan 2 skenario yang sangat mungkin;

  1. database 7 (misalnya) menjadi rusak, terus melayani beberapa permintaan hingga seseorang mengetahui bahwa itu rusak, atau peringatan dari file log ...
  2. Beberapa kueri seperti drop database, drop table, "perbarui di mana ..." ketik kueri borks satu basis data, atau beberapa bagian di dalamnya.

Saat ini saya memiliki banyak dump FULL sebagai file FULL- $ DATE-all-databases.sql.gz, dan diferensial yang dapat diterapkan ke dump FULL sebagai DIFF- $ DATE-all-databases.sql.gz

Untuk mengembalikan database 7 ke beberapa titik-waktu akan memerlukan grep melalui file LENGKAP dan DIFF, dan aplikasi manual sql itu.

Bagaimana cara saya melanjutkan untuk memungkinkan untuk dapat memulihkan ke salah satu dump DIFF sebelumnya ke database master?

APAKAH saya perlu membuat cadangan ke file basis data individual, yaitu

mysqldump --databases "database1" | gzip > database1.sql.gz
mysqldump --databases "database2" | gzip > database2.sql.gz
mysqldump --databases "database3" | gzip > database3.sql.gz

daripada..

mysqldump --master-data --lock--all-databases --all-databases | gzip > all-databases.sql.gz

Jika saya pergi untuk file mysqldump terpisah, apa yang terjadi pada log biner data master, dan apakah saya harus mengatur - master-data untuk kesedihan pemulihan server master?

Tom H
sumber

Jawaban:

7

Jika semua database Anda menggunakan InnoDB saja, saya punya kabar baik.

Anda harus membuang semua database secara paralel dari seorang budak.

Bahkan, Anda bisa memaksa semua database ke titik waktu yang sama.

Hal pertama yang harus diingat tentang seorang Slave adalah bahwa ia tidak diharuskan untuk memiliki logging biner jika itu bukan Master untuk Slave lainnya.

Anda tidak dapat menggunakan --master-dataopsi untuk dump paralel karena setiap dump akan memiliki posisi berbeda yang ditulis pada baris 22 dari setiap file dump. Lebih baik merekam file log terakhir Master dan menempatkan Slave yang dieksekusi menggunakan SHOW SLAVE STATUS\G. Dengan begitu, semua database memiliki posisi point-in-time yang sama.

Anda dapat mengumpulkan semua basis data dan skrip dump paralel dari semua basis data.

DBLIST=/tmp/ListOfDatabasesToParallelDump.txt
BACKUP_BASE=/backups
BACKUP_DATE=`date +"%Y%m%d_%H%M%S"`
BACKUP_HOME=${BACKUP_BASE}/${BACKUP_DATE}
mkdir ${BACKUP_HOME}
cd ${BACKUP_HOME}

mysql -h... -u... -p... -e"STOP SLAVE;"
mysql -h... -u... -p... -e"SHOW SLAVE STATUS\G" > ${SSS}
LOGFIL=`cat ${SSS} | grep "Relay_Master_Log_File" | awk '{print $2}'`
LOGPOS=`cat ${SSS} | grep "Exec_Master_Log_Pos"   | awk '{print $2}'`
echo "Master was at ${LOGFIL} Position ${LOGPOS} for this Backup" > Master_Log_FilePos.txt

mysql -h... -u... -p... -AN -e"SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema','mysql','performance_schema')" > ${DBLIST}

for DB in `cat ${DBLIST}` 
do 
    mysqldump -h... -u... -p... --hex-blob --routines --triggers ${DB} | gzip > ${DB}.sql.gz & 
done 
wait 

mysql -h... -u... -p... -e"START SLAVE;"

Jika ada terlalu banyak basis data, buang 10 atau 20 sekaligus sebagai berikut:

DBLIST=/tmp/ListOfDatabasesToParallelDump.txt
SSS=/tmp/ShowSlaveStatusDisplay.txt
BACKUP_BASE=/backups
BACKUP_DATE=`date +"%Y%m%d_%H%M%S"`
BACKUP_HOME=${BACKUP_BASE}/${BACKUP_DATE}
mkdir ${BACKUP_HOME}
cd ${BACKUP_HOME}

mysql -h... -u... -p... -e"STOP SLAVE;"
mysql -h... -u... -p... -e"SHOW SLAVE STATUS\G" > ${SSS}
LOGFIL=`cat ${SSS} | grep "Relay_Master_Log_File" | awk '{print $2}'`
LOGPOS=`cat ${SSS} | grep "Exec_Master_Log_Pos"   | awk '{print $2}'`
echo "Master was at ${LOGFIL} Position ${LOGPOS} for this Backup" > Master_Log_FilePos.txt

mysql -h... -u... -p... -AN -e"SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema','mysql','performance_schema')" > ${DBLIST}

COMMIT_LIMIT=20
COMMIT_COUNT=0    
for DB in `cat ${DBLIST}` 
do 
    mysqldump -h... -u... -p... --hex-blob --routines --triggers ${DB} | gzip > ${DB}.sql.gz & 
    (( COMMIT_COUNT++ ))
    if [ ${COMMIT_COUNT} -eq ${COMMIT_LIMIT} ]
    then
        COMMIT_COUNT=0
        wait
    fi
done 
wait 
if [ ${COMMIT_COUNT} -gt 0 ]
then
    wait
fi

mysql -h... -u... -p... -e"START SLAVE;"

Jika Anda perlu memulihkan satu tabel, Anda bisa paralel membuang tabel 20 sekaligus dalam urutan ukuran.

Coba ini:

TBLIST=/tmp/ListOfTablesToParallelDump.txt
SSS=/tmp/ShowSlaveStatusDisplay.txt
BACKUP_BASE=/backups
BACKUP_DATE=`date +"%Y%m%d_%H%M%S"`
BACKUP_HOME=${BACKUP_BASE}/${BACKUP_DATE}
mkdir ${BACKUP_HOME}
cd ${BACKUP_HOME}

mysql -h... -u... -p... -e"STOP SLAVE;"
mysql -h... -u... -p... -e"SHOW SLAVE STATUS\G" > ${SSS}
LOGFIL=`cat ${SSS} | grep "Relay_Master_Log_File" | awk '{print $2}'`
LOGPOS=`cat ${SSS} | grep "Exec_Master_Log_Pos"   | awk '{print $2}'`
echo "Master was at ${LOGFIL} Position ${LOGPOS} for this Backup" > Master_Log_FilePos.txt

mysql -h... -u... -p... -AN -e"SELECT CONCAT(table_schema,'.',table_name) FROM information_schema.tables WHERE table_schema NOT IN ('information_schema','mysql','performance_schema') ORDER BY data_length" > ${DBLIST}

COMMIT_LIMIT=20
COMMIT_COUNT=0    
for DBTB in `cat ${TBLIST}` 
do
    DB=`echo "${DBTB}" | sed 's/\./ /g' | awk '{print $1}'`
    TB=`echo "${DBTB}" | sed 's/\./ /g' | awk '{print $2}'`
    DUMPFILE=$DB-{DB}-TBL-${TB}.sql.gz
    mysqldump -h... -u... -p... --hex-blob --routines --triggers ${DB} ${TB} | gzip >  ${DUMPFILE} & 
    (( COMMIT_COUNT++ ))
    if [ ${COMMIT_COUNT} -eq ${COMMIT_LIMIT} ]
    then
        COMMIT_COUNT=0
        wait
    fi
done 
wait 
if [ ${COMMIT_COUNT} -gt 0 ]
then
    wait
fi

mysql -h... -u... -p... -e"START SLAVE;"

Sekarang Anda memiliki skrip untuk membuang basis data atau tabel individual, Anda dapat memuat data itu atas kebijakan Anda. Jika Anda perlu menjalankan SQL dari log biner pada master, Anda dapat menggunakan mysqlbinlogdan memberikannya posisi datetime dan output SQL ke file teks lainnya. Anda hanya perlu melakukan uji tuntas untuk menemukan jumlah data yang Anda butuhkan dari cap waktu apa pun yang dimiliki oleh log bnary. Ingatlah bahwa cap waktu setiap binary log di OS menyatakan bahwa terakhir kali ditulis.

RolandoMySQLDBA
sumber
jawaban brilian thanx. Saya pikir memiliki read-only slave di xfs memberi saya banyak pilihan, dan skrip Anda sangat membantu.
Tom H
dalam skenario di mana saya perlu memulihkan tabel besar untuk master dari cadangan dari slave. Saya hanya perlu membangun kembali tabel pada master, dan apakah semua perubahan mereplikasi ke slave, bahkan jika itu adalah 20GB data? Apakah prosesnya adalah 1) menonaktifkan kunci, 2) menjatuhkan tabel pada master dan slave 3) mengembalikan tabel master 4) mengaktifkan kunci --- dan meminta master mereplikasi semua 20GB ke slave?
Tom H
Jika database ini BUKAN innodb, bisakah saya tetap membuangnya secara paralel?
Tom H
Ya, jika Anda 1) menjadwalkan waktu henti, 2) menjalankan service mysql restart --skip-networking, 3) melakukan dump paralel, 4) menjalankan service mysql restart. Kemudian muat ulang tabel yang Anda butuhkan.
RolandoMySQLDBA
mungkin jika tujuan restart adalah untuk mencegah koneksi jaringan menulis ke database, maka saya dapat mencapai efek yang sama dengan menggunakan iptables i.e. iptables -I INPUT -p tcp --dport 3306 -j DROPpada eth0 dan lo
Tom H