web-dev-qa-db-fra.com

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

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 vidage manuellement, ma connexion au serveur expirera avant la fin du vidage, ce qui m'obligera à réexécuter le vidage. [Je lance actuellement un cron qui fait le vidage tous les soirs, c'est juste pour les vidages que je lance manuellement.]

Existe-t-il un moyen d'accélérer les vidages pour le problème de dépassement de délai de connexion, mais également de limiter la durée d'occupation du serveur par 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.

179
Patrick

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

  • Assurez-vous que votre sortie va sur un ou plusieurs lecteurs différents de celui sur lequel les fichiers de base de données sont stockés - cela fera une énorme différence avec les disques en rotation car les têtes de lecteur ne seront pas constamment en train de basculer entre l'emplacement lu. et l'emplacement vers lequel écrire.
  • 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 via gzip ou similaire. Cela réduira la quantité d'écriture en cours (donc réduisez la charge globale IO, et la quantité de mouvement de la tête) au détriment du temps CPU (que vous pouvez avoir beaucoup de rechange à ces temps de toute façon).
  • En outre, (également ou au lieu de la compression), passez la sortie via un utilitaire de canal (comme pv ) qui prend en charge les grands tampons d'écriture pour regrouper davantage les blocs écrits sur les disques, encore une fois pour réduire l'effet de la tête -mouvement latence - cela fera toute la différence si vous utilisez le --quick option pour réduire l'impact RAM de la sauvegarde de grandes tables).
  • Exécutez votre processus de sauvegarde uniquement lorsque la charge IO est autrement faible.

Vous pouvez cependant résoudre le mauvais problème: il pourrait être plus facile de résoudre les chutes de connexion à la place (bien que la réduction de la charge d'E/S imposée par vos sauvegardes contribuera à réduire l'effet que vous avez sur les autres utilisateurs, il vaut donc la peine d'essayer de toute façon). Pourriez-vous exécuter vos sauvegardes manuelles via écran (ou des outils similaires comme tmux )? De cette façon, si votre connexion au serveur tombe, vous pouvez simplement vous reconnecter et vous reconnecter à la session screen sans qu'aucun processus ne soit interrompu.

Si vous envoyez les données directement via la connexion (c.-à-d. Que vous exécutez mysqldump sur votre machine locale contre une base de données distante, de sorte que le vidage s'affiche localement), vous feriez mieux de commencer par exécuter le vidage sur le serveur, en compressant au besoin, puis en transférant les données sur le réseau à l'aide d'un outil (tel que rsync) qui prend en charge les transferts partiels afin que vous puissiez reprendre le transfert (au lieu de 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 du 1,2 Go de cette table principale vers une autre et la supprimer de celles qui sont copiées par l'appel mysqldump. 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 et peut également vous permettre de répartir les données et la charge d'E/S sur plusieurs disques. La base de données haut de gamme a intégré la prise en charge du 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.

S'éloigner du 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 de l'inactivité, vérifiez les options de votre serveur SSH et de votre client SSH pour faire assurez-vous que les paquets persistants sont activés et envoyés assez souvent. Si vous voyez des chutes même si la connexion est active, vous pouvez également essayer d'utiliser OpenVPN ou similaire pour envelopper la connexion - il devrait gérer une courte chute, même complète si votre connexion entière est interrompue pendant quelques secondes, de sorte que le client SSH et serveur ne remarque pas.

139
David Spillett

APERÇU DE LA SAUVEGARDE AVEC mysqldump

IMHO Faire des sauvegardes est devenu plus 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 simple, le plus simple !!!

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

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

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

Commencez par créer une liste de bases de données (2 techniques pour ce 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 meilleure 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. L'information_schema enregistrerait le dossier en tant que base de données dans la table information_schema.schemata. La technique 2 contournerait les dossiers qui ne contiennent pas de données mysql.

Une fois que vous avez compilé la liste des bases de données, vous pouvez passer en revue la liste et les mysqldump, 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 en même temps, jetez-les en parallèle 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 des tables séparées dans des fichiers de données séparés

Commencez par créer une liste de tableaux

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

Vider ensuite 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 et des techniques pour des instantanés propres

Exemples

  1. Triez la liste des tableaux en fonction de la taille de chaque tableau, croissant ou décroissant.
  2. En utilisant un processus distinct, exécutez "RINCER LES TABLES AVEC VERROUILLAGE EN LECTURE; SÉLECTIONNER LE VEILLE (86400)" avant de lancer mysqldumps. Tuez ce processus une fois mysqldumps terminé. Cela 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.

[~ # ~] mise en garde [~ # ~]

Seule l'option 1 apporte tout. L'inconvénient est que mysqldumps créé de cette façon ne peut être rechargé que dans la même version majot de mysql que le mysqldump a été généré. En d'autres termes, un mysqldump 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 parmi les principales versions.

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

Voici le moyen générique de vider les 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 disposez d'un grand pool de mémoire tampon InnoDB, il est judicieux de le vider du mieux que vous le pouvez avant d'effectuer des sauvegardes. Sinon, MySQL passe le temps à vider les tables avec des pages sales restantes hors du pool de tampons. Voici ce que je propose:

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

SET GLOBAL innodb_max_dirty_pages_pct = 0;

Dans MySQL 5.5, innodb_max_dirty_pages_pct par défaut est 75. Dans MySQL 5.1 et inversement, innodb_max_dirty_pages_pct par défaut est 90. En définissant 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 des validations en deux phases incomplètes des données InnoDB avant d'effectuer tout mysqldump sur les tables InnoDB.

MOT FINAL SUR mysqldump

La plupart des gens évitent mysqldump en faveur d'autres outils et ces outils sont en effet bons.

Ces outils comprennent

  1. MAATKIT (parallèle vidage / restauration scripts, de Percona [obsolète mais génial])
  2. XtraBackup (Sauvegarde d'instantanés TopNotch de Percona)
  3. CDP R1Soft ( Option de module MySQL qui prend des instantanés ponctuels)
  4. MySQL Enterprise Backup (anciennement InnoDB Hot Backups [commercial])

Si vous avez l'esprit d'un vrai DBA MySQL, vous pouvez embrasser mysqldump et avoir la maîtrise complète qui peut être atteinte. Que toutes vos sauvegardes soient le reflet de vos compétences en tant que DBA MySQL .

122
RolandoMySQLDBA

Jetez un œil au maître de réplication MySQL à esclave. Il vous permet de cloner la base de données du maître vers 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 se fait la copie exacte du serveur de base de données maître et/ou de ses bases de données. Il peut y avoir une relation un, un, plusieurs, plusieurs entre maître (s) et esclave (s).

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

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

Réplication MySQL sur la même machine

20
poelinca

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

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

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

Plan D: Instantané d'un esclave - aucun temps d'arrêt.

19
Rick James

Quelques points d'administration d'abord: vous connectez-vous pour faire un ftp ou êtes-vous connecté et il est en train de mourir? Si ssh, assurez-vous d'utiliser écran pour pouvoir reprendre après le plantage de comcast. Si ftp, assurez-vous de le compresser/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. Plus précisément, cela équivaut à utiliser les options --add-drop-table, --add-locks, --all, --quick, --extended-insert, --lock-tables et --disable-keys ensemble. 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 la sortie de vidage lors de la lecture de chaque ligne du serveur, ce qui pourrait être utile pour les grandes tables. Par défaut, mysqldump lit toutes les lignes d'une table en mémoire avant d'écrire la sortie; pour les grandes tables, cela nécessite de grandes quantités de mémoire, ce qui peut entraîner l'échec du vidage.

15
David Hall

J'ai également eu des problèmes avec les délais d'attente lors des vidages de grandes bases de données. J'ai finalement résolu si 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
5
Patrick Heck

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

Pour cela, vous pouvez créer des groupes de tables dans votre schéma et créer un utilisateur DB distinct pour chaque groupe, puis enfin utiliser les autorisations MySQL pour ne pas autoriser l'insertion de tables pour utiliser tous les utilisateurs DB sauf un.

Il s'agit d'une technique éprouvée, rapide, presque parallèle mais pas sûre à 100%, du temps qu'il faudra pour restaurer à partir de grandes décharges comme 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 vidages 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 vidages SQL (mysqldump) pour MySQL"

3
syed