News

Migration logique de MySQL de 5.7 vers 8.0.

le 4 Octobre 2018

Il existe deux manières possibles pour migrer un serveur MySQL 5.7 vers 8.0 : la migration INPLACE et la migration LOGICAL.

La migration INPLACE est généralement préférable, cela consiste à installer MySQL 5.7, importer les données puis upgrader le tout. Cette méthode est bien documentée et vous n'aurez aucun mal à trouver des procédures sur internet.

La méthode LOGICAL consiste, elle, à installer directement MySQL 8.0 puis importer les données préalablement extraites sur un MySQL 5.7 (par mysqldump par exemple). Cette méthode est plus complexe car vous devez vous assurer que le dump en question est compatible. Si pour une raison quelconque vous ne souhaitez pas installer MySQL 5.7 et vous n'avez pas le temps de contrôler votre dump alors cette fiche 'quick & dirty' vous aider à dupliquer rapidement vos données vers MySQL 8.0.

Notez que cette procédure a été pensée pour une installation vierge de MySQL 8.0 pour configurer une réplication Master-Slave avec un MySQL 5.7, l'idée étant de migrer en douceur sans impacter la production. Nous vous déconseillons donc fortement d'utiliser une base MySQL 8.0 déjà active, ou alors réalisez une sauvegarde complète avant !
Enfin, cette procédure ne fonctionnera pas pour des versions antérieures de MySQL (5.5, 5.6 etc...), vous devrez impérativement upgrader en version 5.7 avant.

  1. Import des données

  2. Sur le serveur source, commençons par exporter toutes les bases sans les données, afin de valider plus rapidement l'import :

    mysqldump -u root --all-databases --no-data  --single-transaction --master-data=1 --triggers --routines --events --ignore-table=mysql.innodb_index_stats --ignore-table=mysql.innodb_table_stats | gzip -9 > /tmp/dump-nodata.sql.gz
                

    Copiez le fichier dump-nodata.sql.gz sur le serveur destination et tentez de l'importer sur le serveur MySQL 8.0 :

    gunzip /tmp/dump-nodata.sql.gz
    mysql < /tmp/dump-nodata.sql
                    

    Si vous rencontrez un message d'erreur comme celui ci :
    ERROR 3554 (HY000) at line 8089: Access to system table 'mysql.innodb_index_stats' is rejected.
                    

    Alors ajoutez un paramètre --ignore-table à votre export pour la table concernée et recommencez l'opération (--ignore-table=mysql.innodb_index_stats pour notre exemple )
    Une fois l'import de la structure passé, importez les données, en incluant les éventuels --ignore-table que vous aurez ajouté :
    mysqldump -u root --all-databases --single-transaction --master-data=1 --triggers --routines --events --ignore-table=mysql.innodb_index_stats --ignore-table=mysql.innodb_table_stats | gzip -9 > /tmp/dump.sql.gz
                

    Copiez le fichier dump.sql.gz sur le serveur destination et tentez de l'importer sur le serveur MySQL 8.0 :

    gunzip /tmp/dump.sql.gz
    mysql < /tmp/dump.sql
    

  3. Migration des données

  4. Les données importées sont malheureusement incompatibles avec MySQL 8.0, nous devons donc les migrer. D'autre part, étant donné que nous avons importé la table mysql.user, les mots de passes ont pu changer et l'accès n'est sans doute plus possible.
    Nous allons donc arrêter MySQL et le redémarrer sans contrôle d'accès :

    systemctl stop mysqld
    /sbin/mysqld --skip-grant-tables &
    

    Nous réalisons ensuite la migration des données :
    mysql_upgrade --force
    

    Puis nous nous assurons qu'il n'y a pas de données corrompues :
    mysql_check.sh full
    

    Enfin, si tout c'est bien passé, nous redémarrons MySQL :
    killall -SIGQUIT mysqld
    systemctl start mysqld
    

  5. Vérifications

  6. Assurez vous en premier lieu que vous pouvez vous connecter à la base (attention, les mots de passes sont ceux du serveur source !).

    Ensuite, voici un petit script qui vous permetta de contrôler le nombre de ligne de chaque table, exécutez le sur les serveurs source et destination, le résultat doit être identique :

    for db in $( mysql -Ne 'show databases' | grep -v 'information_schema\|performance_schema\|mysql\|sys' ) ; do 
      for table in $( mysql $db -Ne "show tables" ); do
        count=$( mysql -Ne "select count(*) from \`${db}\`.\`${table}\`" )
        echo -e "${db}.${table}\t${count}"
      done
    done 
    

    Vous pouvez maintenant configurer une réplication Master-Slave standard entre ces deux serveurs car MySQL supporte la réplication entre deux versions qui se suivent : https://dev.mysql.com/doc/refman/8.0/en/replication-compatibility.html