Comment puis-je optimiser un mysqldump d'une grande base de données?

173

J'ai une application symfony avec une base de données InnoDB d'environ 2 Go avec 57 tables. La majorité de la taille de la base de données réside dans une seule table (~ 1,2 Go). J'utilise actuellement mysqldump pour sauvegarder la base de données tous les soirs.

En raison de ma connexion Comcast, souvent, si j'exécute un cliché manuellement, ma connexion au serveur expire avant la fin du cliché, ce qui m'oblige à l'exécuter à nouveau. [Je cours actuellement un cron qui fait le dump tous les soirs, ceci est juste pour les dumps que je lance manuellement.]

Existe-t-il un moyen d'accélérer les vidages pour le problème de délai de connexion, mais également de limiter le temps que le serveur occupe avec ce processus?

BTW, je travaille actuellement sur la réduction de la taille de la base de données globale pour résoudre ce problème.

Patrick
la source
2
Quels paramètres (le cas échéant) passez-vous à la commande mysqldump?
Toby
L'ajout de --compact peut être une option pour vous.
Toby
rien vraiment -mysqldump [database] -u[user] -p'[password]' > db_backup.sql
Patrick
4
Une alternative simple à screenvotre situation serait d'utiliser nohup, cela permettra à votre commande de continuer à s'exécuter sur le serveur, même si votre connexion est interrompue. Par exemple nohup mysqldump [options] > backup.sql 2> backup.err &. Si vous ne fournissez pas de fichier de sortie pour nohup, il sera créé nohup.outpar défaut.
dabest1
1
Jetez un oeil à atet screen(celui - ci si elle est installée, mais atest standard sur tous les unix) ou les ServerAliveIntervaloptions de SSH des façons de traiter avec le pare - feu vous arrêter après la connexion trop longtemps au repos.
MattBianco

Réponses:

134

Le goulot d'étranglement principal dans le vidage comme celui-ci est le lecteur d'E / S. Vous lisez une charge de données et vous l'écrivez à nouveau. Vous pouvez accélérer le processus de plusieurs manières:

  • Assurez-vous que votre sortie est dirigée vers un ou des lecteurs différents de ceux sur lesquels les fichiers de la base de données sont stockés - cela fera une différence énorme avec les disques en rotation, car les têtes de lecteur ne basculeront pas constamment entre l'emplacement en cours de lecture. et l'emplacement en cours d'écriture.
  • La sortie de mysqldump sera très compressible, donc si vous ne pouvez pas séparer la sortie de l'entrée comme mentionné ci-dessus, dirigez la sortie gzipou similaire. Cela réduira la quantité d'écriture en cours (réduisez donc la charge globale d'E / S et le nombre de mouvements de la tête) au détriment d'un certain temps CPU (que vous pourriez avoir beaucoup de temps libre à ces moments-là).
  • En outre, (également ou à la place de la compression), transmettez la sortie via un utilitaire de canal (comme pv ) prenant en charge de grands tampons d'écriture pour regrouper davantage les blocs écrits sur les lecteurs, afin de réduire l'effet de latence des mouvements de la tête. différence si l’on utilise l’ --quickoption pour réduire l’impact en RAM de la sauvegarde de grandes tables).
  • N'exécutez votre processus de sauvegarde que lorsque le chargement d'IO est faible.

Cependant, vous corrigez peut-être le mauvais problème: il serait peut-être plus facile de gérer les interruptions de connexion (bien que réduire la charge d’E / S imposée par vos sauvegardes vous aidera à réduire l’effet que vous avez sur les autres utilisateurs, cela vaut donc la peine d’essayer de toute façon). Pourriez-vous exécuter vos sauvegardes manuelles via l' écran (ou des outils similaires comme tmux )? Ainsi, si votre connexion au serveur est screeninterrompue, vous pouvez simplement vous reconnecter et vous reconnecter à la session sans qu'aucun processus ne soit interrompu.

Si vous envoyez les données directement via la connexion (c'est-à-dire que vous exécutez mysqldump sur votre machine locale avec une base de données distante, de sorte que le vidage apparaisse localement), il vaudrait peut-être mieux l'exécuter d'abord sur le serveur, en le compressant si nécessaire, puis en le transférant. les données sur le réseau en utilisant un outil (tel que rsync) qui prend en charge les transferts partiels afin que vous puissiez reprendre le transfert (au lieu de le redémarrer) si une interruption de connexion l’interrompt.

Dans le cadre de votre "réduction de la taille de la base de données globale pour résoudre ce problème", je suppose qu’une grande partie de vos données ne change pas. Vous pourrez peut-être déplacer une grande partie de 1,2 Go de cette table principale dans une autre et la supprimer de celles copiées par l' mysqldumpappel. Vous n'avez pas besoin de sauvegarder ces données à chaque fois si elles ne changent jamais. Le fractionnement des données entre les tables et les bases de données de cette manière est généralement appelé partitionnement des données. Il peut également vous permettre de répartir les données et le chargement d'E / S sur plusieurs lecteurs. Les bases de données haut de gamme prennent en charge le partitionnement automatique, bien que dans mysql, vous devrez probablement le faire manuellement et modifier votre couche d'accès aux données pour en tenir compte.

Abandonner le sujet pour ce site (vous devriez donc probablement passer à ServerFault ou à SuperUser pour demander si vous avez besoin de plus de détails): Si vous semblez perdre des connexions en raison d'inactivité, vérifiez les options de votre serveur SSH et de votre client SSH pour effectuer les modifications. s'assurer que les paquets persistants sont activés et envoyés assez souvent. Si vous voyez des interruptions même si la connexion est active, vous pouvez également essayer d’utiliser OpenVPN ou un moyen similaire pour encapsuler la connexion - elle devrait gérer une chute courte, voire complète, si votre connexion est en panne pendant quelques secondes, de sorte que le client SSH et le serveur ne remarque pas.

David Spillett
la source
J'aimerais pouvoir réduire le nombre de connexions ssh abandonnées sur mes serveurs. Si je m'attends à ne pas utiliser le terminal plus de 60 secondes environ, je le lance toppour m'assurer que la connexion ne sera pas interrompue. (Et je suis à peu près sûr que c'est la connexion comcast, car nous n'utilisons qu'un routeur WRT standard et un pare-feu au travail et que ma connexion comcast à la maison ne tombe jamais.)
Patrick
J'ai ajouté une petite note spécifique aux connexions SSH.
David Spillett
2
Profondeur et perspicacité dans cette réponse. Vous devriez obtenir un +3 pour cela. Désolé, je ne peux que vous donner +1.
RolandoMySQLDBA
116

Insight dans faire des sauvegardes avec mysqldump

IMHO Faire des sauvegardes est devenu une forme d'art si vous savez comment l'aborder

Vous avez des options

Option 1: mysqldump une instance entière de mysql

C'est le plus facile, le plus simple !!!

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

Tout ce qui est écrit dans un seul fichier: structures de table, index, déclencheurs, procédures stockées, utilisateurs, mots de passe cryptés. D'autres options de mysqldump peuvent également exporter différents styles de commandes INSERT, de fichier journal et de coordonnées de position à partir de journaux binaires, d'options de création de base de données, de données partielles (option --where), etc.

Option 2: bases de données séparées mysqldump dans des fichiers de données séparés

Commencez par créer une liste de bases de données (2 techniques pour le faire)

Technique 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

Technique 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

La technique 1 est le moyen le plus rapide. La technique 2 est la plus sûre et la plus sûre. La technique 2 est préférable car, parfois, les utilisateurs créent des dossiers à usage général dans / var / lib / mysql (datadir) qui ne sont pas liés à la base de données. La classe information_schema enregistrerait le dossier en tant que base de données dans la table information_schema.schemata. La technique 2 contournerait les dossiers ne contenant pas de données mysql.

Une fois que vous avez compilé la liste des bases de données, vous pouvez passer en boucle sur la liste et les copier, même en parallèle si vous le souhaitez.

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

S'il y a trop de bases de données à lancer à la fois, dumpez-les 10 à la fois:

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

Option 3: mysqldump sépare les tables dans des fichiers de données séparés

Commencez par créer une liste de tables

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

Puis videz toutes les tables par groupes de 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

Option 4: UTILISEZ VOTRE IMAGINATION

Essayez des variantes des options susmentionnées, plus des techniques pour des instantanés nets.

Exemples

  1. Ordonnez la liste des tables en fonction de la taille de chaque table, par ordre croissant ou décroissant.
  2. En utilisant un processus séparé, exécutez "FLUSH TABLES WITH READ LOCK; SELECT SLEEP (86400)" avant de lancer mysqldumps. Tuez ce processus une fois que mysqldumps est terminé. Ceci est utile si une base de données contient à la fois InnoDB et MyISAM.
  3. Enregistrez les mysqldumps dans des dossiers datés et faites pivoter les anciens dossiers de sauvegarde.
  4. Chargez toute l'instance mysqldumps sur des serveurs autonomes.

CAVEAT

Seule l'option 1 apporte tout. L'inconvénient est que mysqldumps créé de cette manière ne peut être rechargé que dans la même version majeure de mysql que celle créée par mysqldump. En d'autres termes, un mysqldump à partir d'une base de données MySQL 5.0 ne peut pas être chargé en 5.1 ou 5.5. La raison ? Le schéma mysql est totalement différent entre les versions majeures.

Les options 2 et 3 n'incluent pas la sauvegarde des noms d'utilisateur et des mots de passe.

Voici le moyen générique de dump des subventions SQL pour les utilisateurs, qui est lisible et plus portable.

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

L'option 3 n'enregistre pas les procédures stockées. Vous pouvez donc effectuer les opérations suivantes.

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

Un autre point à noter concerne InnoDB. Si vous avez un pool de mémoire tampon InnoDB important, il est judicieux de le vider le mieux possible avant toute sauvegarde. Sinon, MySQL passe le temps nécessaire pour vider les tables de la page sale restante du pool de mémoire tampon. Voici ce que je suggère:

Environ 1 heure avant la sauvegarde, exécutez cette commande SQL

SET GLOBAL innodb_max_dirty_pages_pct = 0;

Innodb_max_dirty_pages_pct est 75 par défaut dans MySQL 5.5. Dans MySQL 5.1 et versions antérieures, innodb_max_dirty_pages_pct par défaut est 90. Si vous définissez innodb_max_dirty_pages_pct sur 0, cela accélérera le vidage des pages sales sur le disque. Cela empêchera ou au moins atténuera l'impact du nettoyage de toute validation incomplète en deux phases des données InnoDB avant d'effectuer toute opération mysqldump sur les tables InnoDB.

FINAL WORD SUR mysqldump

La plupart des gens hésitent à utiliser mysqldump au profit d'autres outils, qui sont vraiment bons.

Ces outils incluent

  1. MAATKIT (parallèle sauvegarde / restauration de scripts, de Percona [Obsolète mais grand])
  2. XtraBackup (Sauvegarde de capture instantanée TopNotch de Percona)
  3. CDP R1Soft ( Option de module MySQL prenant des instantanés à un instant donné)
  4. MySQL Enterprise Backup (anciennement InnoDB Hot Backups [commercial])

Si vous avez l’esprit d’un véritable administrateur de base de données MySQL, vous pouvez adopter mysqldump et en maîtriser parfaitement la maîtrise. Que toutes vos sauvegardes soient le reflet de vos compétences en tant que DBA MySQL .

RolandoMySQLDBA
la source
2
+1 pour une utilisation agréable de mysqldump ainsi que pour: Si vous avez l’esprit d’un véritable administrateur de base de données MySQL, vous pouvez embrasser mysqldump et en obtenir la maîtrise complète. Que toutes vos sauvegardes soient le reflet de vos compétences en tant que DBA MySQL .... Bonnes lignes !!!
Abdul Manaf,
4
Dans InnoDB, les tables de vidage individuellement vous donneront une sauvegarde incohérente.
Alain Collins
5
@AlainCollins c'est pourquoi j'utilise mysqldumps sur un esclave de réplication en lecture seule. Une fois que Seconds_Behind_Master a la valeur 0, vous exécutez STOP SLAVE. Maintenant, vous avez un moment cohérent pour faire mysqldumps dans l’un des styles susmentionnés. Je l'ai fait pour des sociétés de négoce en ligne au cours des 5 dernières années sans même se plaindre auprès de moi ou des propriétaires de ma société. A partir de ce moment, je mets en parallèle mysqldumps toutes les 10 minutes pour ce client. Je le fais également pour d'autres clients afin de fournir des périodes de sauvegarde plus rapides.
RolandoMySQLDBA
J'ai une base de données de 32 Go, donc l'option 3 correspond exactement à ce que j'avais en tête! Merci!
Raymond
Je dois sauvegarder et réimporter 1 To de données pour réduire considérablement le volume ibdata1. À l’époque des disques SSD protégés par un RAID matériel, l’option 3 est la seule solution pour moi.
Rabudde
18

Regardez maître de réplication MySQL pour esclave. Il vous permet de cloner la base de données du maître sur un autre serveur de base de données avec la même base de données. Cela inclut les identités maître et esclave. Slave crée lui-même la copie exacte du serveur de base de données maître et / ou de ses bases de données. Il peut exister une relation un-un-un-plusieurs-plusieurs entre un (des) maître (s) et un (des) esclave (s).

L'esclave lit en permanence le journal binaire chez le maître (le journal bin stocke les requêtes écrites sur le serveur de base de données maître) et est entré dans son serveur de base de données esclave. (cela signifie que votre base de données principale ne sera pas du tout affectée)

La bonne nouvelle est que cela n'affectera pas trop votre serveur MySQL, car vous ne remarquerez pas de temps morts ni de réponses aux requêtes lentes. Nous l'utilisons pour les bases de données de 10 Go et cela fonctionne comme un charme sans temps d'arrêt.

Réplication MySQL sur la même machine

poelinca
la source
Bien que cela fonctionne pour moi, je pense que cela pourrait être un peu exagéré. Je n'ai actuellement pas besoin de ce niveau de sauvegarde, même si je garderai cela à l'esprit si les exigences de l'application changeaient.
Patrick le
4
+1 pour la sauvegarde d'un réplica afin de supprimer la charge d'E / S de la sauvegarde de la base de données principale et de réduire les problèmes potentiels de verrouillage, avec une mise en garde importante: soyez prudent avec l'option "réplica sur la même machine" que vos opérations sur l'esclave peut concurrencer le maître pour la bande passante d'E / S - assurez-vous que les fichiers de données de l'esclave sont un disque / une matrice différent de celui du maître afin d'atténuer ce problème.
David Spillett
1
Idem sur le commentaire de David Splllet. J'ai configuré et entretenu des dizaines de maîtres / esclaves avec des sauvegardes mysqldump sur les esclaves pour My Web Hosting Employer. +1 de moi aussi.
RolandoMySQLDBA
16

Plan A: Voir aussi Xtrabackup de Percona. Cela permet une sauvegarde en ligne d’InnoDB, sans aucun verrouillage important.

Plan B: un esclave peut être arrêté et vous pouvez effectuer une sauvegarde cohérente de plusieurs manières (copier des fichiers, mysqldump, xtrabackup, etc.)

Plan C: Instantané LVM. Après une configuration cryptique, le temps d’arrêt pour une sauvegarde est inférieur à une minute, quelle que soit la taille de la base de données. Vous arrêtez mysqld, faites la capture instantanée, redémarrez mysqld, puis copiez la capture instantanée. La dernière étape peut prendre beaucoup de temps, mais MySQL n’est pas en panne.

Plan D: Instantané d’un esclave - zéro temps d’arrêt.

Rick James
la source
2
Hourra aux quatre plans. Je ne peux donner que 0,25 par réponse !!! +1 (4 x 0,25)
RolandoMySQLDBA
15

Quelques points d’administration d’abord: vous connectez-vous pour faire un ftp ou êtes-vous ssh'ed et c’est en train de mourir? Si ssh, veillez à utiliser screen pour pouvoir reprendre après le crash de Comcast. Si ftp, assurez-vous de compresser le fichier / tar avant l'envoi.

Essayez également le paramètre --opt ou --quick

--opt Cette option active un ensemble d'options supplémentaires pour rendre les opérations de vidage et de rechargement plus efficaces. En particulier, cela revient à utiliser les options --add-drop-table, --add-locks, --all, --quick, --extended-insert, --lock-tables et --disable-keys. Notez que cette option rend la sortie moins portable et moins susceptible d'être comprise par d'autres systèmes de base de données.

--quick Cette option indique à mysqldump d'écrire le résultat de la sauvegarde car il lit chaque ligne du serveur, ce qui peut s'avérer utile pour les grandes tables. Par défaut, mysqldump lit toutes les lignes d'une table en mémoire avant d'écrire le résultat. pour les grandes tables, cela nécessite de grandes quantités de mémoire, ce qui peut éventuellement entraîner l'échec du dump.

David Hall
la source
1
Est-ce que --opt ne va pas augmenter la taille du fichier qui finira par sortir?
Toby
Il va ajouter un peu - je voulais dire - rapide qui est plus en réponse à son problème .... édition maintenant. Merci!
David Hall
+1 pour l'écran, ce qui évite complètement ce problème
Gaius
+1 pour une réponse très agréable et concise pour les explications --opt et --quick de mysqldump.
RolandoMySQLDBA
1
--opt est activé par défaut.
Jordanie
5

J'avais aussi des problèmes avec les délais d'attente lors du dump de grandes bases de données. J'ai finalement résolu if en envoyant des commandes individuelles pour chaque table de la base de données et en ajoutant tout à un fichier comme celui-ci:

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
la source
4
Ceci est considéré comme une sauvegarde "incohérente", dans la mesure où, lors de la restauration, des données d'une table peuvent être mappées sur une autre mais n'existent pas.
Morgan Tocker
3

Je pense que la question est de savoir comment restaurer plus rapidement à partir de fichiers de vidage créés par mysqldump, et non d'une solution de sauvegarde différente.

Pour ce faire, vous pouvez notamment créer des groupes de tables dans votre schéma et créer un utilisateur de base de données distinct pour chaque groupe, puis utiliser les autorisations MySQL pour ne pas autoriser l'insertion de tables dans l'utilisation de tous les utilisateurs sauf un.

Il s’agit d’une technique éprouvée, rapide et presque parallèle, mais qui n’est pas sûre à 100% du temps nécessaire à la restauration à partir de gros vidages tels que 500G ou plus. Mais à mon humble avis, vous avez besoin de quelque chose de parallèle. Consultez le lien ci-dessous pour un exemple.

[Restauration rapide et parallèle à partir de dumps SQL (mysqldump) pour MySQL] [1]

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

"Restauration rapide et parallèle à partir de dumps SQL (mysqldump) pour MySQL"

syed
la source
2
Ceci est une copie exacte de votre réponse à une autre question. Vous voudrez peut-être personnaliser un peu plus pour cette question spécifique.
Paul White
La question ne porte spécifiquement sur la façon de restaurer plus rapidement.
Andrew Lorien