Flux de travail DDL transactionnel pour MySQL

25

J'ai été un peu surpris de découvrir que les instructions DDL ( alter table, create indexetc.) engagent implicitement la transaction actuelle dans MySQL. Venant de MS SQL Server, la possibilité de faire des modifications de base de données dans une transaction localement (qui a ensuite été annulée) était une partie importante de mon flux de travail. Pour une intégration continue, la restauration a été utilisée si la migration a eu un hoquet pour une raison quelconque, de sorte qu'au moins nous n'avons pas laissé la base de données dans un état semi-migré.

Comment les gens résolvent-ils ces deux problèmes lorsqu'ils utilisent MySQL avec des migrations et une intégration continue?

sennett
la source
Croix postée de SO. stackoverflow.com/q/28197013/614523 N'a pas obtenu beaucoup d'amour là-bas.
sennett
1
Pour l'intégration continue, considérez les instantanés LVM comme un moyen de créer très rapidement un environnement entier dans un état connu.
Rick James
5
Vous pouvez toujours passer à Postgres - il prend en charge le DDL transactionnel (SCNR).
a_horse_with_no_name
3
Je suis d'accord avec @a_horse_with_no_name, si c'est votre flux de travail, envisagez sérieusement l'utilisation de PosgreSQL, qui a DDL transactionnel avec de nombreuses autres fonctionnalités intéressantes.
Renzo

Réponses:

9

Pour de nombreuses personnes, le talon d'Achille MySQL est une validation implicite.

Selon la page 418, paragraphe 3, du livre

Guide d'étude de certification MySQL 5.0

les commandes suivantes peuvent et vont interrompre une transaction

  • ALTER TABLE
  • BEGIN
  • CREATE INDEX
  • DROP DATABASE
  • DROP INDEX
  • DROP TABLE
  • RENAME TABLE
  • TRUNCATE TABLE
  • LOCK TABLES
  • UNLOCK TABLES
  • SET AUTOCOMMIT = 1
  • START TRANSACTION

SUGGESTION

En ce qui concerne MySQL, tous les travaux ContinuousIntegration (CI) / SelfService que vous construisez doivent toujours rendre les travaux transactionnels et les scripts DDL mutuellement exclusifs.

Cela vous donne la possibilité de créer des paradigmes qui

  • prendre en charge les transactions correctement isolées avec des START TRANSACTION/COMMITblocs
  • contrôle de DDL en écrivant vous-même le script DDL, en exécutant ce DDL en tant que constructeur ou destructeur
    • Constructeur: DDL pour créer des tableaux avec un nouveau design
    • Destructor: DDL pour faire revenir les tableaux à la conception précédente
  • ne combinez jamais ces opérations sous un même emploi

AVERTISSEMENT: si vous utilisez MyISAM pour tout cela, vous pouvez (dé) gentiment ajouter MyISAM à la liste des choses qui peuvent interrompre une transaction, peut-être pas en termes de validation implicite, mais certainement en termes de cohérence des données si un retour en arrière devait jamais être nécessaire.

POURQUOI PAS LVM?

Les instantanés LVM sont excellents et la restauration d'instances entières de bases de données sans avoir à effectuer un traitement SQL lourd est idéale. Cependant, en ce qui concerne MySQL, vous devez tenir compte de deux moteurs de stockage: InnoDB et MyISAM.

Base de données All-InnoDB

Regardez l'architecture d'InnoDB (avec l'aimable autorisation de Percona CTO Vadim Tkachenko)

Plomberie InnoDB

InnoDB a de nombreuses pièces mobiles

  • Espace disque logique du système
    • Dictionnaire de données
    • Double tampon d'écriture (prise en charge de la cohérence des données; utilisé pour la récupération après incident)
    • Insérer un tampon (modifications des tampons vers des index secondaires non uniques)
    • Segments de restauration
    • Annuler l'espace (où la croissance la plus incontrôlée peut se produire)
  • Piscine tampon InnoDB
    • Pages de données sales
    • Pages d'index sales
    • Modifications des index non uniques
  • Autres caches de mémoire importants

Prendre un instantané LVM d'une base de données entièrement InnoDB avec des modifications non validées flottant dans le pool de tampons et les caches de mémoire produirait un ensemble de données qui nécessiterait une récupération après incident InnoDB une fois le LUN restauré et mysqld démarré.

SUGGESTION POUR TOUS-InnoDB

Si vous pouvez arrêter MySQL avant de prendre un instantané

    1. Courir SET GLOBAL innodb_fast_shutdown = 0;
    1. Courir SET GLOBAL innodb_max_dirty_pages_pct = 0;
    1. Courir SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
    1. Répétez l'étape 3 jusqu'à ce que Innodb_buffer_pool_pages_dirty soit 0 ou aussi proche de 0 que possible
    1. service mysql stop
    1. Prendre un instantané LVM
    1. service mysql stop

Si vous ne pouvez pas arrêter mais prendre un instantané avec MySQL Live

    1. Courir SET GLOBAL innodb_max_dirty_pages_pct = 0;
    1. Courir SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
    1. Répétez l'étape 2 jusqu'à ce que Innodb_buffer_pool_pages_dirty soit 0 ou aussi proche de 0 que possible
    1. Prendre un instantané LVM
    1. Courir SET GLOBAL innodb_max_dirty_pages_pct = 75;

Base de données All-MyISAM ou Mix InnoDB / MyISAM

MyISAM, lorsqu'il est consulté, conserve un nombre de descripteurs de fichiers ouverts par rapport à celui-ci. Si MySQL plante, toute table MyISAM avec un nombre de descripteurs de fichiers ouverts> 0 sera marquée comme crash et nécessitant une réparation (même si rien ne va pas avec les données).

Prendre un instantané LVM d'une base de données qui utilise des tables MyISAM aura une ou plusieurs tables MyISAM à réparer lorsque l'instantané est restauré et mysqld démarré.

SUGGESTION POUR All-MyISAM ou InnoDB / MyISAM Mix

Si vous pouvez arrêter MySQL avant de prendre un instantané

    1. Courir SET GLOBAL innodb_fast_shutdown = 0;
    1. Courir SET GLOBAL innodb_max_dirty_pages_pct = 0;
    1. Courir SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
    1. Répétez l'étape 3 jusqu'à ce que Innodb_buffer_pool_pages_dirty soit 0 ou aussi proche de 0 que possible
    1. service mysql stop
    1. Prendre un instantané LVM
    1. service mysql stop

Si vous ne pouvez pas arrêter mais prendre un instantané avec MySQL Live

Vous pouvez appliquer un vidage de certaines tables InnoDB

    1. Courir SET GLOBAL innodb_max_dirty_pages_pct = 0;
    1. Courir SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
    1. Répétez l'étape 2 jusqu'à ce que Innodb_buffer_pool_pages_dirty soit 0 ou aussi proche de 0 que possible
    1. Exécuter FLUSH TABLES innodb_tbl1,... FOR EXPORT;sur des tables critiques InnoDB
    1. Courir FLUSH TABLES WITH READ LOCK;
    1. Prendre un instantané LVM
    1. Courir UNLOCK TABLES;
    1. Courir SET GLOBAL innodb_max_dirty_pages_pct = 75;

La réplication MySQL pourrait-elle aider?

Bien que vous puissiez restaurer un instantané LVM sur deux serveurs et configurer la réplication maître / esclave MySQL, cela devient une source supplémentaire de nettoyage lors de la restauration des instantanés.

Si vous exécutez des travaux CI sur un maître et que ces travaux sont petits, la réplication peut être un gain de temps dans certaines circonstances. Vous pouvez simplement exécuter STOP SLAVE;sur l'esclave, lancer les travaux CI sur le maître et exécuter START SLAVE;sur l'esclave lorsque les données du maître sont certifiées.

Si les travaux CI alertent trop de données, vous pouvez restaurer un instantané LVM et configurer la réplication à partir de zéro. Si vous faites cela souvent, vous pourriez probablement le faire avec la configuration de la réplication MySQL.

DERNIÈRES PENSÉES

  • Il est préférable d'utiliser plusieurs serveurs DB (3 ou plus) pour effectuer des restaurations et des tests de régression.
  • Convertissez les tables MyISAM restantes en InnoDB si ces tables n'ont pas besoin de rester MyISAM.
  • Si le contenu de vos données est sensible, vous devez exécuter un travail CI pour nettoyer les données après avoir restauré un instantané avant de lancer des tests. Vous pouvez également prendre des instantanés de MySQL avec les données déjà nettoyées.
RolandoMySQLDBA
la source
4

Si vous parlez d'intégration continue, je suppose que c'est un environnement de développement. Dans ce cas, je dirais que la personne qui effectue des changements structurels doit les tester pour s'assurer de ne pas casser les choses pour les autres, de la même manière que quelqu'un qui met à jour une bibliothèque commune: testez dans votre propre bac à sable avant de valider de telles modifications.

Dans un processus de déploiement en production, vous passez généralement par des environnements de développement, d'assurance qualité ou même de pré-production pour tester vos modifications, de la même manière que pour toute modification de code.

Notez que ce n'est pas spécifique à MySQL: les bases de données Oracle feraient aussi implicitement COMMIT lors de l'émission de 'alter table' etc.

Maintenant, si vous voulez vous protéger, vous pouvez bien sûr faire une sauvegarde au préalable, ou un instantané LVM ou système de fichiers si votre système peut le faire. Vous pouvez également avoir un esclave que vous pourriez retarder / arrêter comme sécurité avant les opérations sensibles.

phil_w
la source