Bagaimana saya bisa mengoptimalkan mysqldump dari database besar?

173

Saya memiliki aplikasi symfony dengan database InnoDB yang ~ 2GB dengan 57 tabel. Mayoritas ukuran basis data berada dalam satu tabel (~ 1.2GB). Saat ini saya menggunakan mysqldump untuk mem-backup database setiap malam.

Karena koneksi comcast saya, seringkali jika saya menjalankan dump secara manual koneksi saya ke server akan habis sebelum dump selesai menyebabkan saya harus menjalankan kembali dump. [Saat ini saya menjalankan cron yang melakukan dump setiap malam, ini hanya untuk dump yang saya jalankan secara manual.]

Apakah ada cara untuk mempercepat kesedihan untuk masalah waktu tunggu koneksi, tetapi juga untuk membatasi waktu server sibuk dengan proses ini?

BTW, saya saat ini sedang bekerja untuk mengurangi ukuran keseluruhan database untuk menyelesaikan masalah ini.

Patrick
sumber
2
Parameter apa (jika ada) yang Anda berikan ke perintah mysqldump?
Toby
Menambahkan --kompak mungkin menjadi opsi untuk Anda.
Toby
tidak ada yang benar-benar -mysqldump [database] -u[user] -p'[password]' > db_backup.sql
Patrick
4
Alternatif sederhana screenuntuk situasi Anda adalah menggunakan nohup, itu akan memungkinkan perintah Anda untuk terus berjalan di server, bahkan jika koneksi Anda terputus. Misalnya nohup mysqldump [options] > backup.sql 2> backup.err &. Jika Anda tidak menyediakan file output untuk nohup, itu akan membuat nohup.outsecara default.
dabest1
1
Lihat atdan screen(yang terakhir jika diinstal, tetapi atstandar pada semua unix) atau ServerAliveIntervalopsi untuk SSH untuk cara menangani firewall yang mematikan Anda setelah koneksi idle terlalu lama.
MattBianco

Jawaban:

134

Hambatan utama dalam dump seperti ini adalah drive I / O. Anda membaca banyak data dan menulisnya lagi. Anda dapat mempercepat ini dalam beberapa cara:

  • Pastikan output Anda pergi ke drive yang berbeda dari yang disimpan oleh file database - ini akan membuat perbedaan besar dengan disk berputar karena kepala drive tidak akan terus-menerus menjentikkan antara lokasi yang sedang dibaca dari dan lokasi yang sedang ditulis.
  • Output dari mysqldump akan sangat kompresibel, jadi jika Anda tidak dapat memisahkan output dari input seperti yang disebutkan di atas, pipa keluaran melalui gzipatau serupa. Ini akan mengurangi jumlah penulisan yang dilakukan (jadi kurangi keseluruhan muatan IO, dan jumlah pergerakan head) dengan mengorbankan beberapa waktu CPU (yang mungkin Anda punya banyak waktu luang).
  • Selain itu, (juga atau bukan kompresi) meneruskan output melalui utilitas pipa (seperti pv ) yang mendukung buffer tulis besar ke blok grup yang ditulis ke drive bersama-sama lebih banyak, sekali lagi untuk mengurangi efek latensi head-movement - ini akan membuat cukup berbeda jika menggunakan --quickopsi untuk mengurangi dampak RAM dari membuat cadangan tabel besar).
  • Jalankan proses pencadangan Anda hanya jika IO memuat rendah.

Namun, Anda mungkin memperbaiki masalah yang salah: mungkin lebih mudah untuk mengatasi penurunan koneksi (meskipun mengurangi beban I / O yang dikenakan oleh cadangan Anda akan membantu mengurangi efek yang Anda miliki pada pengguna lain sehingga tetap layak untuk dicoba). Bisakah Anda menjalankan backup manual Anda melalui layar (atau alat serupa seperti tmux )? Dengan begitu, jika koneksi Anda ke server screenterputus, Anda dapat menyambung kembali dan menyambung kembali ke sesi tersebut tanpa ada proses yang terganggu.

Jika Anda mengirim data secara langsung melalui koneksi (mis. Anda menjalankan mysqldump pada mesin lokal Anda terhadap basis data jauh, sehingga dump muncul secara lokal), Anda mungkin lebih baik menjalankan dump pada server terlebih dahulu, mengompresi sesuai kebutuhan, kemudian mentransfer data melalui jaringan menggunakan alat (seperti rsync) yang mendukung transfer parsial sehingga Anda dapat melanjutkan transfer (alih-alih memulai ulang) jika koneksi terputus.

Sebagai bagian dari "mengurangi ukuran keseluruhan basis data untuk menyelesaikan masalah ini", saya kira sebagian besar data Anda tidak berubah. Anda mungkin dapat memindahkan potongan besar 1.2Gb dari tabel utama ke yang lain dan menghapusnya dari yang disalin oleh mysqldumppanggilan. Anda tidak perlu membuat cadangan data ini setiap kali jika tidak pernah berubah. Membagi data antara tabel dan basis data dengan cara ini biasanya disebut sebagai partisi data dan juga dapat memungkinkan Anda untuk menyebarkan data dan I / O memuat lebih dari beberapa drive. Basis data kelas atas telah mendukung pemartisian otomatis, meskipun dalam mysql Anda mungkin harus melakukannya secara manual dan mengubah lapisan akses data Anda untuk memperhitungkannya.

Menyimpang dari topik untuk situs ini (jadi Anda mungkin harus beralih ke ServerFault atau SuperUser untuk menanyakan apakah Anda memerlukan lebih detail): Jika Anda tampaknya kehilangan koneksi karena tidak aktif, periksa opsi di server SSH Anda dan klien SSH untuk membuat Pastikan paket keep-live diaktifkan dan dikirim cukup sering. Jika melihat penurunan bahkan jika koneksi aktif, Anda juga dapat mencoba menggunakan OpenVPN atau serupa untuk membungkus koneksi - itu harus menangani setetes, bahkan setetes jika seluruh koneksi Anda turun selama beberapa detik, sehingga klien SSH dan server tidak memperhatikan.

David Spillett
sumber
Saya berharap bisa mengurangi jumlah koneksi ssh yang terputus ke server saya. Jika saya berharap untuk tidak menggunakan terminal lebih lama dari ~ 60 detik saya jalankan topuntuk memastikan koneksi tidak turun. (Dan saya cukup yakin itu koneksi comcast karena kami hanya menggunakan router WRT standar & firewall di tempat kerja dan koneksi comcast rumah saya tidak pernah turun)
Patrick
Saya telah menambahkan catatan singkat khusus untuk koneksi SSH.
David Spillett
2
Kedalaman dan wawasan dalam jawaban ini. Anda harus mendapatkan +3 untuk ini. Maaf, saya hanya bisa memberi Anda +1.
RolandoMySQLDBA
116

WAWASAN KE DALAM MELAKUKAN BACKUPS DENGAN mysqldump

IMHO Melakukan pencadangan telah menjadi bentuk seni jika Anda tahu cara mendekatinya

Anda punya opsi

Opsi 1: mysqldump seluruh contoh mysql

Ini adalah yang termudah, no-brainer !!!

mysqldump -h... -u... -p... --hex-blob --routines --triggers --all-databases | gzip > MySQLData.sql.gz

Semuanya ditulis dalam satu file: struktur tabel, indeks, pemicu, prosedur tersimpan, pengguna, kata sandi terenkripsi. Opsi mysqldump lainnya juga dapat mengekspor berbagai gaya perintah INSERT, file log, dan koordinat posisi dari log biner, opsi pembuatan basis data, data sebagian (opsi di mana), dan sebagainya.

Opsi 2: mysqldump memisahkan database menjadi file data terpisah

Mulailah dengan membuat daftar database (2 teknik untuk melakukan ini)

Teknik 1

mysql -h... -u... -p... -A --skip-column-names -e"SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema','mysql')" > ListOfDatabases.txt

Teknik 2

mysql -h... -u... -p... -A --skip-column-names -e"SELECT DISTINCT table_schema FROM information_schema.tables WHERE table_schema NOT IN ('information_schema','mysql')" > ListOfDatabases.txt

Teknik 1 adalah cara tercepat. Teknik 2 adalah yang paling pasti dan paling aman. Teknik 2 lebih baik karena, kadang-kadang, pengguna membuat folder untuk keperluan umum di / var / lib / mysql (datadir) yang tidak terkait database. Information_schema akan mendaftarkan folder sebagai database di tabel information_schema.schemata. Teknik 2 akan memotong folder yang tidak berisi data mysql.

Setelah Anda mengompilasi daftar database, Anda dapat melanjutkan untuk mengulang daftar dan mysqldump mereka, bahkan secara paralel jika diinginkan.

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

Jika ada terlalu banyak basis data untuk diluncurkan pada satu waktu, paralel membuangnya 10 sekaligus:

COMMIT_COUNT=0
COMMIT_LIMIT=10
for DB in `cat ListOfDatabases.txt`
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
if [ ${COMMIT_COUNT} -gt 0 ]
then
    wait
fi

Opsi 3: mysqldump tabel terpisah menjadi file data terpisah

Mulailah dengan membuat daftar tabel

mysql -h... -u... -p... -A --skip-column-names -e"SELECT CONCAT(table_schema,'.',table_name) FROM information_schema.tables WHERE table_schema NOT IN ('information_schema','mysql')" > ListOfTables.txt

Kemudian buang semua tabel dalam kelompok 10

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

Opsi 4: GUNAKAN IMAGINASI ANDA

Coba variasi Pilihan yang disebutkan di atas ditambah teknik untuk snapshot bersih

Contohnya

  1. Pesanlah daftar tabel dengan ukuran masing-masing tabel naik atau turun.
  2. Menggunakan proses terpisah, jalankan "FLUSH TABLES WITH READ LOCK; SELECT SLEEP (86400)" sebelum meluncurkan mysqldumps. Matikan proses ini setelah mysqldumps selesai. Ini berguna jika database berisi InnoDB dan MyISAM
  3. Simpan mysqldumps di folder bertanggal dan putar keluar folder cadangan yang lama.
  4. Muat seluruh contoh mysqldumps ke server mandiri.

CAVEAT

Hanya Opsi 1 yang membawa semuanya. Kekurangannya adalah mysqldumps yang dibuat dengan cara ini hanya bisa dimuat ulang ke versi rilis mysql majot yang sama dengan mysqldump yang dihasilkan. Dengan kata lain, mysqldump dari database MySQL 5.0 tidak dapat dimuat dalam 5.1 atau 5.5. Alasannya ? Skema mysql sangat berbeda di antara rilis utama.

Opsi 2 dan 3 tidak termasuk menyimpan nama pengguna dan kata sandi.

Berikut adalah cara umum untuk membuang SQL Grants untuk pengguna yang mudah dibaca dan lebih portabel

mysql -h... -u... -p... --skip-column-names -A -e"SELECT CONCAT('SHOW GRANTS FOR ''',user,'''@''',host,''';') FROM mysql.user WHERE user<>''" | mysql -h... -u... -p... --skip-column-names -A | sed 's/$/;/g' > MySQLGrants.sql

Opsi 3 tidak menyimpan prosedur yang tersimpan, sehingga Anda dapat melakukan hal berikut

mysqldump -h... -u... -p... --no-data --no-create-info --routines > MySQLStoredProcedures.sql &

Poin lain yang harus diperhatikan adalah tentang InnoDB. Jika Anda memiliki kumpulan buffer InnoDB besar, masuk akal untuk menyiramnya sebaik mungkin sebelum melakukan backup apa pun. Jika tidak, MySQL menghabiskan waktu membersihkan tabel dengan halaman kotor yang tersisa dari buffer pool. Inilah yang saya sarankan:

Sekitar 1 jam sebelum melakukan pencadangan, jalankan perintah SQL ini

SET GLOBAL innodb_max_dirty_pages_pct = 0;

Di MySQL 5.5 default innodb_max_dirty_pages_pct adalah 75. Di MySQL 5.1 dan kembali, innodb_max_dirty_pages_pct default adalah 90. Dengan menetapkan innodb_max_dirty_pages_pct ke 0, ini akan mempercepat pembilasan halaman kotor ke disk. Ini akan mencegah atau setidaknya mengurangi dampak pembersihan setiap komitmen dua fase dari data InnoDB sebelum melakukan mysqldump terhadap tabel InnoDB.

FINAL WORD ON mysqldump

Kebanyakan orang menghindar dari mysqldump demi alat-alat lain dan alat-alat itu memang bagus.

Alat-alat tersebut termasuk

  1. MAATKIT ( skrip dump / restore paralel , dari Percona [Sudah usang tapi bagus])
  2. XtraBackup (Cadangan Snapshot TopNotch dari Percona)
  3. CDP R1Soft ( Opsi Modul MySQL yang mengambil snapshot point-in-time)
  4. MySQL Enterprise Backup (sebelumnya InnoDB Hot Backups [komersial])

Jika Anda memiliki semangat DBA MySQL yang benar, Anda dapat merangkul mysqldump dan memiliki penguasaan penuh atas hal itu yang dapat dicapai. Semoga semua cadangan Anda mencerminkan keterampilan Anda sebagai DBA MySQL .

RolandoMySQLDBA
sumber
2
+1 untuk penggunaan mysqldump dan juga untuk: Jika Anda memiliki semangat DBA MySQL yang benar, Anda dapat merangkul mysqldump dan memiliki penguasaan penuh atas hal itu yang dapat dicapai. Semoga semua cadangan Anda mencerminkan keterampilan Anda sebagai DBA MySQL .... Garis yang bagus !!!
Abdul Manaf
4
Di InnoDB, membuang tabel secara individual akan memberi Anda cadangan yang tidak konsisten.
Alain Collins
5
@AlainCollins inilah sebabnya saya menjalankan mysqldumps pada replikasi slave yang hanya bisa dibaca. Setelah Seconds_Behind_Master adalah 0, Anda menjalankan STOP SLAVE. Sekarang Anda memiliki titik waktu yang konsisten untuk melakukan mysqldumps dalam gaya yang disebutkan di atas. Saya telah melakukan ini untuk perusahaan perdagangan online selama 5 tahun terakhir tanpa banyak keluhan kepada saya atau pemilik perusahaan saya. Sampai saat ini, saya melakukan paralel mysqldumps setiap 10 menit untuk klien ini. Saya juga melakukan ini untuk klien lain untuk menyediakan periode cadangan yang lebih cepat.
RolandoMySQLDBA
Saya memiliki 32GB db jadi opsi 3 adalah persis apa yang ada dalam pikiran saya! Terima kasih!
Raymond
Saya harus mencadangkan dan mengimpor kembali 1TB data untuk menyusut sangat besar ibdata1. Pada masa SSD yang didukung oleh RAID perangkat keras, opsi 3 adalah satu-satunya solusi bagi saya.
rabudde
18

Lihatlah master replikasi MySQL menjadi slave. Ini memungkinkan Anda untuk mengkloning database master ke server database lain dengan database yang sama. Itu termasuk identitas master dan slave. Slave menjadikan dirinya sendiri salinan tepat dari server database master dan atau databasenya. Mungkin ada satu-satu, satu-banyak, banyak-satu hubungan antara tuan dan budak.

Slave terus membaca log biner di master (log bin menyimpan kueri yang ditulis di server database master) dan mendapatkan input ke server database slave-nya. (Ini berarti database master Anda tidak akan terpengaruh sama sekali)

Kabar baiknya adalah bahwa itu tidak akan mempengaruhi server MySQL Anda terlalu banyak karena Anda tidak akan melihat downtime atau memperlambat respons permintaan. Kami menggunakannya untuk basis data 10Gb dan berfungsi seperti jimat tanpa downtime.

Replikasi MySQL Pada Mesin Yang Sama

poelinca
sumber
sementara itu akan bekerja untuk saya, saya pikir itu mungkin sedikit berlebihan. Saat ini saya tidak memerlukan tingkat cadangan, meskipun saya akan mengingat ini jika persyaratan aplikasi berubah.
Patrick
4
+1 untuk mencadangkan replika untuk menghapus beban IO cadangan dari DB utama, dan mengurangi potensi masalah terkait penguncian, dengan satu peringatan signifikan: berhati-hatilah dengan opsi "replika pada mesin yang sama" seperti operasi Anda pada slave dapat bersaing dengan master untuk bandwidth IO - pastikan file data slave adalah drive / array yang berbeda dari master untuk mengurangi masalah ini.
David Spillett
1
Ditto pada Komentar David Splllet. Saya mengatur dan memelihara puluhan Master / Budak dengan backup mysqldump pada slave untuk Majikan Hosting Web Saya. +1 dari saya juga.
RolandoMySQLDBA
16

Paket A: Lihat juga Xtrabackup dari Percona. Ini memungkinkan pencadangan online InnoDB, tanpa penguncian signifikan.

Plan B: Seorang Budak dapat dihentikan, dan Anda dapat mengambil cadangan yang konsisten dengan salah satu dari beberapa cara (menyalin file, mysqldump, xtrabackup, dll)

Paket C: Cuplikan LVM. Setelah beberapa penyiapan samar, downtime untuk cadangan kurang dari satu menit, terlepas dari ukuran database. Anda berhenti mysqld, lakukan snapshot, restart mysqld, lalu salin snapshot. Langkah terakhir bisa memakan waktu lama, tetapi MySQL tidak down.

Plan D: Snapshot of a Slave - nol downtime.

Rick James
sumber
2
Hoorah untuk keempat rencana. Saya hanya bisa memberi +0,25 per jawaban !!! +1 (4 x 0,25)
RolandoMySQLDBA
15

Beberapa poin admin pertama: Apakah Anda terhubung untuk melakukan ftp atau Anda ssh'ed dan sedang sekarat? Jika ssh, maka pastikan untuk menggunakan layar sehingga Anda dapat melanjutkan setelah comcast crash. Jika ftp, maka pastikan Anda mengompres / tar sebelum pengiriman.

Coba juga parameter --opt atau --quick

--opt Opsi ini mengaktifkan seperangkat opsi tambahan untuk membuat operasi dump dan memuat ulang lebih efisien. Secara khusus, ini setara dengan menggunakan opsi --add-drop-table, --add-locks, --all, --quick, --extended-insert, --lock-tables, dan --disable-keys bersamaan. Perhatikan bahwa opsi ini membuat output lebih mudah dibawa-bawa dan kecil kemungkinannya untuk dipahami oleh sistem basis data lainnya.

--quick Opsi ini memberitahu mysqldump untuk menulis output dump saat membaca setiap baris dari server, yang mungkin berguna untuk tabel besar. Secara default, mysqldump membaca semua baris dari sebuah tabel ke dalam memori sebelum menulis output; untuk tabel besar, ini membutuhkan sejumlah besar memori, mungkin menyebabkan dump gagal.

David Hall
sumber
1
Akankah --opt tidak meningkatkan ukuran file yang pada akhirnya akan mendapatkan output?
Toby
Ini akan menambahkan beberapa - saya bermaksud menambahkan --quick yang lebih sebagai jawaban untuk masalahnya .... mengedit sekarang. Terima kasih!
David Hall
+1 untuk layar, yang sama sekali menghindari masalah ini
Gayus
+1 untuk jawaban yang sangat bagus dan ringkas untuk penjelasan myoptqldump --opt dan --quick.
RolandoMySQLDBA
1
--opt aktif secara default.
Jordan
5

Saya dulu punya masalah dengan timeout selama kesedihan database besar juga. Saya akhirnya menyelesaikan jika dengan mengirimkan perintah individual untuk setiap tabel di db dan menambahkan everthing ke satu file seperti ini:

TABLES=`mysql -u $USER -p$PWD -Bse 'show tables' $DB`
for TABLE in $TABLES
do
    mysqldump -u $USER -p$PWD $DB $TABLE >> dump.sql
done
Patrick Heck
sumber
4
Ini dianggap sebagai cadangan "tidak konsisten", karena setelah dipulihkan Anda mungkin memiliki data dalam satu tabel yang memetakan yang lain tetapi tidak ada.
Morgan Tocker
3

Saya pikir pertanyaannya adalah tentang bagaimana memulihkan lebih cepat dari file dump yang dibuat mysqldump, bukan solusi cadangan yang berbeda.

Salah satu cara, Anda dapat melakukan ini adalah dengan membuat grup tabel dalam skema Anda, dan membuat pengguna DB yang terpisah untuk setiap grup kemudian akhirnya menggunakan izin MySQL untuk tidak membiarkan tabel dimasukkan dengan menggunakan semua kecuali satu pengguna DB.

Ini adalah teknik yang terbukti, cepat, hampir paralel tetapi tidak 100% yakin, berapa lama untuk memulihkan dari dump besar seperti 500G atau lebih. Tapi menurut saya, Anda perlu sesuatu yang paralel. Lihat tautan di bawah untuk contoh.

[Cepat, pengembalian paralel dari SQL dumps (mysqldump) untuk MySQL] [1]

http://geeksww.com/tutorials/database_management_systems/mysql/tips_and_tricks/fast_parallel_restore_from_sql_dumps_mysqldump_for_mysql.php

"Cepat, pemulihan paralel dari SQL dumps (mysqldump) untuk MySQL"

Syed
sumber
2
Ini adalah salinan jawaban Anda untuk pertanyaan lain. Anda mungkin ingin mengubahnya sedikit lebih banyak untuk pertanyaan khusus ini.
Paul White
Pertanyaannya secara khusus BUKAN tentang cara mengembalikan lebih cepat.
andrew lorien