L'exécution d'une instruction ALTER TABLE sur une table volumineuse peut bloquer toutes les nouvelles transactions pendant plusieurs minutes, voire plusieurs heures. Lorsqu'une instruction DDL bloquante maintient la file d'attente des requêtes de verrouillage MDL-X ouverte, chaque transaction accédant à cette table s'accumule derrière elle. Si cette file devient trop longue, l'épuisement des connexions risque de provoquer l'indisponibilité totale de votre application. Les instructions DDL non bloquantes éliminent ce risque : l'instruction DDL tente d'obtenir le verrou par cycles courts et libère sa position dans la file d'attente entre chaque tentative, permettant ainsi aux nouvelles transactions de continuer à s'exécuter.
Fonctionnement
Le système de verrouillage des métadonnées (MDL) de MySQL protège les tables lors des modifications de schéma. Une instruction DDL bloquante demande un verrou exclusif MDL-X et bloque la file d'attente des requêtes jusqu'à l'obtention de ce verrou. Le verrou MDL-X bénéficiant de la priorité la plus élevée, toute nouvelle transaction accédant à la table se retrouve en attente derrière l'instruction DDL, même si cette dernière patiente encore pour qu'une transaction plus ancienne se termine.
Les instructions DDL non bloquantes modifient ce comportement :
L'instruction DDL tente d'acquérir le verrou MDL-X dans un délai d'expiration court (
loose_polar_nonblock_ddl_lock_wait_timeout, 1 seconde par défaut).Si le verrou est indisponible, l'instruction DDL libère entièrement sa position dans la file d'attente. La file n'étant plus bloquée, les transactions en attente et entrantes peuvent acquérir leurs propres verrous et se poursuivre normalement.
Après un intervalle configurable (
loose_polar_nonblock_ddl_retry_interval, 6 secondes par défaut), l'instruction DDL effectue une nouvelle tentative.Les étapes 2 et 3 se répètent jusqu'à atteindre le nombre défini par
loose_polar_nonblock_ddl_retry_times.
Pendant les intervalles de nouvelle tentative, la table reste pleinement accessible. Le nombre de transactions par seconde (TPS) peut diminuer brièvement lorsque l'instruction DDL acquiert le verrou, mais ne tombe jamais à zéro.
Les instructions DDL non bloquantes ont une priorité inférieure à celle des instructions DDL bloquantes et présentent un risque plus élevé de ne pas obtenir le verrou MDL-X. Privilégiez-les lorsque la continuité de service prime sur la rapidité de modification du schéma.
Versions prises en charge
Les instructions DDL non bloquantes nécessitent l'une des versions suivantes :
PolarDB for MySQL 8.0.1 en version de révision 8.0.1.1.29 ou ultérieure
PolarDB for MySQL 8.0.2 en version de révision 8.0.2.2.12 ou ultérieure
Pour vérifier la version de révision de votre cluster, consultez Versions du moteur 5.6, 5,7 et 8.0.
Instructions DDL prises en charge
La prise en charge des instructions DDL non bloquantes dépend de votre version de révision.
| Version de révision | Instructions prises en charge | Notes |
|---|---|---|
| 8.0.1.1.29 ou ultérieure, ou 8.0.2.2.12 | ALTER TABLE uniquement |
Pour défragmenter une table InnoDB, utilisez ALTER TABLE table_name ENGINE=InnoDB au lieu de OPTIMIZE TABLE table_name |
| 8.0.2.2.13 ou ultérieure | ALTER TABLE, OPTIMIZE TABLE, TRUNCATE TABLE |
— |
Activer les instructions DDL non bloquantes
Ces quatre paramètres sont définis au niveau de la session. Configurez-les dans la même session avant d'exécuter l'instruction DDL.
Étape 1 : Activer le mode DDL non bloquant
SET SESSION loose_polar_nonblock_ddl_mode = ON;
La valeur par défaut de loose_polar_nonblock_ddl_mode est OFF.
Étape 2 : Configurer le comportement de nouvelle tentative
SET SESSION loose_polar_nonblock_ddl_retry_times = 4194304;
SET SESSION loose_polar_nonblock_ddl_retry_interval = 6;
SET SESSION loose_polar_nonblock_ddl_lock_wait_timeout = 1;
| Paramètre | Valeur par défaut | Valeurs valides | Unité | Quand modifier |
|---|---|---|---|---|
loose_polar_nonblock_ddl_retry_times |
0 (dérivé de lock_wait_timeout) |
0–31536000 | — | Définissez cette valeur sur 4194304 pour les modifications de schéma longues sur des tables volumineuses |
loose_polar_nonblock_ddl_retry_interval |
6 | 1–31536000 | Secondes | Augmentez cette valeur pour réduire la contention des verrous ; diminuez-la pour accélérer l'exécution de l'instruction DDL |
loose_polar_nonblock_ddl_lock_wait_timeout |
1 | 1–31536000 | Secondes | Augmentez cette valeur si le verrou n'est pas obtenu assez fréquemment sous une charge d'écriture importante |
Pour plus d'informations sur l'application de ces paramètres, consultez Configurer les paramètres du cluster et du nœud.
Étape 3 : Exécuter l'instruction DDL
ALTER TABLE table_name ADD INDEX index_name (column1, column2, column3);
L'instruction s'exécute avec un comportement non bloquant pour la session en cours. Les autres sessions ne sont pas affectées.
Test de performance
Les tests suivants comparent les instructions DDL bloquantes, les instructions DDL non bloquantes et l'outil de modification de schéma en ligne gh-ost à l'aide de SysBench. Pour plus d'informations sur SysBench, consultez Test de performance OLTP.
Test environment: PolarDB for MySQL 8,0, Cluster Edition, 8 cœurs CPU, 64 Go de mémoire.
Configuration
-
Créez une table contenant 1 million de lignes :
./oltp_read_write.lua --mysql-host="Cluster endpoint" --mysql-port="Port number" \ --mysql-user="Username" --mysql-password="Password" \ --mysql-db="sbtest" --tables=1 --table-size=1000000 \ --report-interval=1 --percentile=99 --threads=8 --time=6000 prepare -
Simulez une charge de travail en lecture/écriture :
./oltp_read_write.lua --mysql-host="Cluster endpoint" --mysql-port="Port number" \ --mysql-user="Username" --mysql-password="Password" \ --mysql-db="sbtest" --tables=1 --table-size=1000000 \ --report-interval=1 --percentile=99 --threads=8 --time=6000 run -
Maintenez un verrou MDL en démarrant une transaction et en la laissant ouverte :
/* Session 1 */ BEGIN; SELECT * FROM sbtest1; -
Dans une seconde session, ajoutez une colonne à la table :
/* Session 2 */ ALTER TABLE sbtest1 ADD COLUMN d INT; -
Répétez la modification du schéma à l'aide de gh-ost (nécessite la journalisation binaire, voir Activer la journalisation binaire) :
./gh-ost --assume-rbr --user="Username" --password="Password" \ --host="Cluster endpoint" --port="Port number" \ --database="sbtest" --table="sbtest1" --alter="ADD COLUMN d INT" \ --allow-on-master --aliyun-rds \ --initially-drop-old-table --initially-drop-ghost-table --execute
Impact sur le TPS
DDL bloquant (DDL non bloquant désactivé) : le TPS chute à zéro et y reste jusqu'à la fin de l'instruction DDL.

DDL non bloquant : le TPS diminue périodiquement lorsque l'instruction DDL tente d'obtenir le verrou, mais ne tombe jamais à zéro. L'impact sur l'activité est minime.

gh-ost : le TPS chute périodiquement à zéro. gh-ost fonctionne en créant une table fantôme, en y appliquant les modifications, puis en renommant atomiquement cette table fantôme pour remplacer l'originale (étape de basculement). Ce basculement nécessite un verrouillage bref de la table, ce qui provoque les chutes périodiques du TPS.

Comparaison des vitesses sur 100 millions de lignes
Des colonnes ont été ajoutées à une table de 100 millions de lignes à l'aide d'instructions DDL non bloquantes (algorithmes INSTANT, INPLACE et COPY) et de gh-ost.
Sans charge de travail : les instructions DDL non bloquantes s'exécutent plus rapidement que gh-ost.

Avec charge de travail en lecture/écriture : les instructions DDL non bloquantes restent plus rapides que gh-ost.

Les instructions DDL non bloquantes maintiennent le TPS au-dessus de zéro tout au long de la modification du schéma et s'exécutent plus rapidement que gh-ost, tant en l'absence de charge que sous des charges similaires à celles d'un environnement de production.
Rubriques associées
Si vous avez des questions concernant les opérations DDL, contactez-nous.