Mirajv1.0
FR

17. L'outil de migration miraj-migrate

miraj-migrate copie une base SQL existante (schéma, vues et lignes) vers un serveur MIRAJ en marche. Il lit la source en lecture seule, par le protocole réseau : la source n'est ni arrêtée ni modifiée, et l'outil peut donc être rejoué autant de fois que nécessaire avant la bascule.

17.1 Migration facilitée depuis un serveur du protocole hérité#

La source est un serveur SQL joint par le protocole hérité, celui que parle aussi MIRAJ en langage MIRAJ : la migration ne demande donc pas de réécrire vos requêtes ni de changer de connecteur applicatif (pilote JDBC, ODBC, PDO, etc.). Concrètement :

  1. Migrer les données avec miraj-migrate run (voir §17.3).
  2. Pointer vos applications vers le serveur MIRAJ en ne changeant que l'hôte et le port dans leur chaîne de connexion — le port de la source (3306 en général) devient 7007 (MIRAJ). Le compte, le mot de passe et le nom de la base restent inchangés une fois les comptes recréés (§17.6).
  3. Redémarrer les applications : elles continuent d'envoyer les mêmes requêtes SQL, avec le même connecteur, sans modification de code.

Cette compatibilité couvre le langage SQL et le protocole de connexion courants. Les objets propres au moteur d'origine (déclencheurs, routines stockées, événements, comptes et privilèges) ne sont pas copiés automatiquement : voir §17.6, « Ce qui n'est pas migré ».

17.2 Syntaxe générale#

miraj-migrate inspect --source-db <base> [options de la source]
miraj-migrate run     --source-db <base> [options de la source et de la cible]
                      [--drop-existing] [--skip-data] [--batch-rows <n>] [--only t1,t2]
miraj-migrate --help

Codes de sortie :

CodeSignification
0Succès : tout est migré et vérifié
1Erreur (option invalide, connexion impossible, base source inconnue) ou au moins un objet en échec

La source est toujours lue par le protocole hérité (--source-protocol est sans effet). La cible est jointe dans le protocole de son langage, reconnu à la connexion (--protocol auto, défaut ; voir 17.8).

17.3 Commandes#

CommandeEffet
inspectListe les tables de la base source avec leur nombre de lignes, les vues, puis les objets qui ne seront pas migrés (déclencheurs, routines, événements). N'écrit rien. À lancer en premier pour évaluer le chantier.
runCrée la base cible si elle n'existe pas, y recrée les tables puis les vues, copie les lignes et vérifie chaque table.

17.4 Options#

Source

OptionDescriptionDéfaut
--source-db <base>Base à migrer (obligatoire).—
--source-host <hôte>Hôte du serveur source.127.0.0.1
--source-port <port>Port du serveur source.3306
--source-user <compte>Compte de lecture.root
--source-passwordMot de passe du compte, demandé au clavier sans être affiché (aussi --source-ask-password).aucun
--source-password=<mot de passe>Mot de passe écrit sur la ligne de commande (déconseillé, voir plus bas).—
--source-ssl, --source-ssl-ca <fichier.pem>, --source-ssl-insecure, --source-no-sslChiffrement de la connexion à la source (voir « Chiffrement TLS » ci-dessous).TLS proposé
--source-protocol …Accepté sans effet : la source est toujours lue par le protocole hérité.—

Sans --source-password, le mot de passe est lu dans la variable d'environnement MIRAJ_SOURCE_PASSWORD si elle existe.

Cible (serveur MIRAJ)

OptionDescriptionDéfaut
--host <hôte>Hôte du serveur MIRAJ.127.0.0.1
--port <port>Port du serveur MIRAJ.7007
--user <compte>Compte à utiliser (droits de création de base et de table).root
--passwordMot de passe, demandé au clavier sans être affiché (aussi --ask-password).aucun
--password=<mot de passe>Mot de passe écrit sur la ligne de commande (déconseillé).—
--ssl, --ssl-ca <fichier.pem>, --ssl-insecure, --no-sslChiffrement de la connexion au serveur MIRAJ.TLS proposé
--db <base>Base créée sur le serveur MIRAJ.nom de la base source
--protocol auto|miraj|postgresqlLangage de l'instance cible : reconnu à la connexion (auto), ou imposé (voir 17.8).auto

Sans --password, le mot de passe est lu dans la variable d'environnement MIRAJ_PASSWORD si elle existe.

Comportement de run

OptionDescription
--drop-existingSupprime d'abord les tables et vues de même nom sur la cible. Sans cette option, une table déjà présente est un échec (erreur 1050) et n'est pas touchée.
--skip-dataNe recrée que le schéma, sans copier les lignes.
--only t1,t2Ne migre que les tables et vues nommées (noms séparés par des virgules, casse ignorée).
--batch-rows <n>Nombre maximal de lignes par INSERT (défaut 500 ; un INSERT est aussi coupé à 1 Mio de SQL).

Mot de passe. Écrit sur la ligne de commande (--password=secret, ou --password secret comme dans les versions précédentes), il est visible par les autres utilisateurs de la machine dans la liste des processus : l'outil affiche alors un avertissement. En usage interactif, donner --password seul : il est demandé au clavier, sans écho. Dans un script, utiliser les variables d'environnement (MIRAJ_PASSWORD, MIRAJ_SOURCE_PASSWORD), définies par le planificateur ou par un fichier lisible du seul compte de service (droits 0600 sous Linux). Un mot de passe qui commence par un tiret s'écrit --password=-motdepasse.

Chiffrement TLS. Les deux connexions (source et cible) sont réglées séparément, les options de la source portant le préfixe --source- :

OptionEffet
(aucune)TLS proposé : la connexion est chiffrée si le serveur annonce TLS, en clair sinon. Le certificat n'est pas vérifié : protège d'une écoute passive, pas d'un intermédiaire actif.
--sslTLS exigé ; le certificat du serveur doit être signé par une autorité publique reconnue ou par celle de --ssl-ca, et valable pour le nom d'hôte ou l'adresse de --host.
--ssl-ca <fichier.pem>Autorité (fichier PEM, un ou plusieurs certificats) qui a signé le certificat du serveur, par exemple un certificat autosigné copié depuis le serveur. Implique --ssl.
--ssl-insecureTLS exigé, certificat accepté sans vérification, avec un avertissement. Pour un essai seulement.
--no-sslConnexion en clair.

Côté MIRAJ, TLS s'active avec --tls-cert et --tls-key au démarrage du serveur (chapitre 15) ; --require-tls refuse alors les connexions en clair.

17.5 Déroulement d'une migration#

  1. Connexion à la source et à la cible (les deux en UTF-8 complet, emoji compris) ; création de la base cible si nécessaire. Sur la cible, la session de migration coupe le contrôle des clés étrangères (FOREIGN_KEY_CHECKS = 0) et la durée maximale d'une instruction (max_statement_time = 0), qu'une écriture en masse pourrait dépasser.
  2. Pour chaque table (les séquences d'abord, une valeur par défaut pouvant appeler NEXTVAL) : lecture de sa définition sur la source, création sur la cible (avec --drop-existing, suppression préalable) avec le prochain numéro AUTO_INCREMENT de la source, puis copie des lignes par INSERT multi-lignes.
  3. Vérification : le nombre de lignes de la source, celui des lignes lues et celui de la cible doivent être identiques.
  4. Pour chaque vue : création sur la cible, puis lecture de contrôle (SELECT … LIMIT 1). Le compte DEFINER de la source est retiré, car il n'existe généralement pas sur la cible. Une vue qui dépend d'une vue pas encore créée est reprise à la passe suivante, tant qu'une passe en crée au moins une.
  5. Bilan : nombre de tables migrées, nombre d'échecs, objets à reprendre à la main ; le détail des échecs est écrit sur la sortie d'erreur (- table x : …).

Les tables sont traitées l'une après l'autre ; un échec sur une table n'arrête pas les suivantes. Les contraintes de clé étrangère sont recréées avec la table ; la copie se fait sans vérification de l'ordre entre tables, la source ayant déjà garanti la cohérence.

Exemple :

> miraj-migrate inspect --source-db gestion --source-host 10.0.0.5 --source-user lecture
Base source « gestion » ([email protected]:3306) : 2 table(s), 1 vue(s)
  table clients                                          3001 ligne(s)
  table lignes                                          15005 ligne(s)
  vue   v_soldes
Total : 18006 ligne(s)
À reprendre manuellement — déclencheurs : maj_solde

> miraj-migrate run --source-db gestion --source-host 10.0.0.5 --source-user lecture --drop-existing
Migration de « gestion » ([email protected]:3306) vers « gestion » ([email protected]:7007, langage MIRAJ)
  table clients                                          3001 ligne(s) copiée(s), vérifiée(s)
  table lignes                                          15005 ligne(s) copiée(s), vérifiée(s)
  vue   v_soldes                                 créée
À reprendre manuellement — déclencheurs : maj_solde
Bilan : 2 table(s) migrée(s), 0 échec(s)

17.6 Ce qui n'est pas migré#

  • Déclencheurs, routines stockées et événements : vers une cible en langage MIRAJ, ils sont seulement listés (« À reprendre manuellement »). Leur corps dépend du dialecte de la source et doit être relu, puis recréé avec le SQL de MIRAJ (chapitres 6 et 7). Vers une cible en langage PostgreSQL, routines et déclencheurs sont traduits en PL/pgSQL quand c'est possible (17.8).
  • Comptes et privilèges : à recréer avec CREATE USER et GRANT (chapitre 14).
  • Écritures concurrentes : la copie n'est pas un instantané. Pour une base encore utilisée, suspendre les écritures pendant run, ou relancer run --drop-existing juste avant la bascule.
  • Contenu : la vérification compare des nombres de lignes, pas les valeurs. Pour un contrôle plus fort, comparer des agrégats ou une empreinte par table sur les deux serveurs.

Les définitions de tables sont rejouées telles que la source les fournit : une clause que MIRAJ refuse apparaît comme un échec de cette table, avec le message d'erreur du serveur MIRAJ (chapitre 27).

La clause ENGINE suit la même règle : une table InnoDB de la source devient une table en mémoire de MIRAJ, une table Aria ou MyISAM devient une table disque (<table>.dmrj, chapitre 6, « Moteurs de stockage »). Pour garder en mémoire une table volumineuse déclarée MyISAM à la source, ou l'inverse, changer le moteur après la migration par ALTER TABLE … ENGINE = ….

17.7 Messages d'erreur courants#

MessageCause
--source-db est obligatoireBase source non indiquée.
commande « x » inconnue / option « x » inconnue / --batch-rows : entier > 0 attenduCommande autre que inspect ou run, option mal écrite, valeur de --batch-rows invalide.
connexion source (…) impossible / connexion cible (…) impossibleHôte, port ou compte incorrect, ou serveur arrêté.
TLS exigé, mais le serveur ne le propose pas--ssl, --ssl-ca ou --ssl-insecure donné, et le serveur n'a pas de certificat (--tls-cert).
certificat du serveur refusé (…)Certificat signé par une autorité inconnue, expiré, ou établi pour un autre nom : indiquer l'autorité avec --ssl-ca, et joindre le serveur par le nom (ou l'adresse) que porte son certificat.
base source « x » : erreur SQL 1049La base source n'existe pas.
création : erreur SQL 1050La table existe déjà sur la cible : ajouter --drop-existing.
nombre de lignes : source …, lues …, cible …Écarts après copie : vérifier le journal du serveur (--log) et relancer.
vue créée mais illisibleLa vue référence un objet absent de la cible (table en échec, fonction non portée).

17.8 Cible en langage PostgreSQL#

Une instance cible en langage PostgreSQL (élément POSTGRESQL de sql_mode, voir chapitre 29) est reconnue à la connexion (--protocol auto, ou --protocol postgresql pour l'imposer). La migration y diffère sur trois points :

  • définitions récrites : le CREATE TABLE et le CREATE VIEW de la source sont relus par MIRAJ et écrits en langage PostgreSQL (identifiants "…", types PostgreSQL, index en CREATE INDEX, TINYINT(1) en boolean, ENUM gardé) ; une définition que MIRAJ ne relit pas met la table ou la vue en échec (« définition non convertible en langage PostgreSQL ») ;
  • lignes chargées par COPY … FROM STDIN (format texte), au fil de la lecture de la source, en une instruction par table : une erreur n'écrit aucune ligne de la table ; --batch-rows est sans objet. Les octets s'envoient en \x…, les dates et nombres dans leur texte ;
  • routines et déclencheurs traduits en PL/pgSQL (sans --only) : chaque procédure, fonction et déclencheur de la source est relu (SHOW CREATE) puis traduit au mieux — blocs, variables, IF, CASE, boucles étiquetées, curseurs sans paramètre, gestionnaires EXIT (clause EXCEPTION), gestionnaire CONTINUE HANDLER FOR NOT FOUND d'une seule affectation, SIGNAL (RAISE) ; un déclencheur devient une fonction RETURNS trigger de même nom et un CREATE TRIGGER … EXECUTE FUNCTION. Une construction sans traduction (SELECT qui rend des lignes au client, variables @x, curseurs à paramètres, autres gestionnaires CONTINUE, SQLWARNING, instructions de session…) ou une définition refusée par la cible donne un avertissement qui cite la définition en commentaire, sans compter comme échec. Écart de la traduction : un SELECT … INTO sans ligne met ses cibles à NULL en PL/pgSQL (MIRAJ les laisse inchangées). Les événements restent listés (« À reprendre manuellement »).

Le contrôle final (nombre de lignes source et cible) est le même.