Comment dépanner une tâche AWS DMS qui échoue avec le message d'erreur « ERROR: canceling statement due to statement timeout » (ERREUR : annulation de l'instruction en raison de l'expiration de son délai d'exécution) ?

Dernière mise à jour : 16/02/2021

Je migre des données vers ou depuis ma base de données PostgreSQL sur site à l'aide d'AWS Database Migration Service (AWS DMS). La tâche AWS DMS s'exécute normalement pendant un certain temps, puis échoue avec un message d'erreur. Comment dépanner et résoudre ces erreurs?

Brève description

Si la base de données PostgreSQL est la source de votre tâche de migration, AWS DMS extrait les données de la table pendant la phase de chargement complet. Ensuite, AWS DMS lit à partir des « write-ahead logs » (WAL) qui sont conservés par l'emplacement de réplication pendant la phase de capture des données modifiées (CDC).

Si la base de données PostgreSQL est la cible de votre tâche de migration, AWS DMS extrait les données de la source et crée des fichiers CSV dans l'instance de réplication. Ensuite, AWS DMS exécute une commande COPY (COPIER) pour insérer ces enregistrements dans la cible pendant la phase de chargement complet. Toutefois, au cours de la phase CDC, AWS DMS exécute les instructions DML exactes à partir des journaux WAL sources en mode d'application transactionnelle. Pour le mode d'application par lots, AWS DMS crée également des fichiers CSV pendant la phase CDC et exécute une commande COPY (COPIER) pour insérer les modifications nettes dans la cible.

AWS DMS utilise le paramètre de délai d'expiration par défaut de 60 secondes lorsqu'AWS DMS exécute les commandes pour obtenir des données de la source ou pour placer des données dans la cible. Si la source ou la cible est fortement chargée ou si les tables contiennent des verrous, AWS DMS aura besoin de plus de 60 secondes pour exécuter ces commandes. Par conséquent, la tâche échoue avec une erreur indiquant « canceling statement due to statement timeout » (annulation de l'instruction en raison de l'expiration de son délai d'exécution). Vous voyez alors l'une des entrées suivantes dans le journal :

Messages :

« ]E:  wal_slot_create(...) - Unable to create slot 'xxxxxxxxxxxxxxxx_00016391_c4a70947_84c9_4a55_8d54_ff63f2f69a52' (on execute(...) phase) [1020101]  (postgres_endpoint_wal_utils.c:3215) »

Procédez comme suit pour dépanner et résoudre ces erreurs :

  • Identifiez la cause de longs délais d'exécution des commandes.
  • Augmentez la valeur du délai d'exécution et vérifiez la valeur du délai de création de l'emplacement.
  • Dépannez les problèmes de création de l'emplacement.

Résolution

Identifiez la cause de longs délais d'exécution des commandes

Pour rechercher la commande qui n'a pas pu être exécutée pendant la période d'exécution, consultez le journal des tâches AWS DMS et la section des statistiques de table de la tâche. Vous pouvez également trouver ces informations dans le fichier du journal des erreurs PostgreSQL si le paramètre log_min_error_statement est défini sur ERROR ou a une gravité inférieure. Après avoir identifié la commande qui a échoué, vous pouvez trouver les noms des tables ayant échoué. Consultez l'exemple de message d'erreur suivant tiré du journal des erreurs PostgreSQL :

ERROR: canceling statement due to statement timeout 
STATEMENT: <The statement executed>"

Pour trouver des verrous sur les tables associées, exécutez la commande suivante dans la source ou la cible (selon l'endroit où l'erreur s'affiche) :

SELECT blocked_locks.pid AS blocked_pid,
 blocked_activity.usename AS blocked_user,
 blocking_locks.pid AS blocking_pid,
         blocking_activity.usename AS blocking_user, 
         blocked_activity.query    AS blocked_statement,
         blocking_activity.query   AS current_statement_in_blocking_process
   FROM  pg_catalog.pg_locks         blocked_locks 
    JOIN pg_catalog.pg_stat_activity blocked_activity  ON blocked_activity.pid = blocked_locks.pid
    JOIN pg_catalog.pg_locks         blocking_locks 
        ON blocking_locks.locktype = blocked_locks.locktype 
        AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE
        AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
        AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
        AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
        AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
        AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
        AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
        AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
        AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
        AND blocking_locks.pid != blocked_locks.pid 
    JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
   WHERE NOT blocked_locks.GRANTED;

Si vous trouvez des PID bloqués, arrêtez ou « tuez » le PID bloqué en exécutant la commande suivante :

SELECT pg_terminate_backend(blocking_pid); 

Comme les lignes mortes ou les « tuples » peuvent augmenter le temps de SELECT, recherchez un grand nombre de lignes mortes dans les tables sources en exécutant la commande suivante :

select * from pg_stat_user_tables where relname= 'table_name';

Vérifiez si la table cible ayant échoué comporte ou non des clés primaires ou des index uniques. S'il n'y a pas de clés primaires ou d'index uniques, cela entraîne une analyse complète de la table pendant l'exécution d'une instruction UPDATE, ce qui prend beaucoup de temps.

Augmentation de la valeur du délai d'exécution

AWS DMS utilise l'attribut de connexion supplémentaire executeTimeout dans les points de terminaison source et cible. La valeur par défaut de executeTimeout est 60 secondes. AWS DMS expire donc si l'exécution d'une requête prend plus de 60 secondes.

Si l'erreur s'affiche dans Source_Unload ou Source_Capture, définissez la valeur de délai pour executeTimeout dans la source. Si l'erreur s'affiche dans Target_Load ou Target_Apply, définissez la valeur de délai d'expiration pour executeTimeout dans la cible. Procédez comme suit pour augmenter le paramètre de valeur de délai d'exécution :

1.    Ouvrez la console AWS DMS.

2.    Choisissez Endpoints (Points de terminaison) dans le panneau de navigation.

3.    Choisissez le point de terminaison PostgreSQL.

4.    Choisissez Actions, puis sélectionnez « Modify » (Modifier).

5.    Développez la section « Endpoint specific settings » (Paramètres spécifiques aux points de terminaison).

6.    Dans le champ « Extra connection attributes » (Attributs de connexion supplémentaires), entrez la valeur suivante:

executeTimeout=3600;

7.    Choisissez Enregistrer.

8.    Dans le panneau Endpoints (Points de terminaison), choisissez le nom de votre point de terminaison PostgreSQL.

9.    Dans la section Connections (Connexions) le Statut du point de terminaison passe de Testing (Test en cours) à Successful (Réussite).

Vous pouvez augmenter (en millisecondes) le paramètre statement_timeout dans l'instance de base de données PostgreSQL. La valeur par défaut est 0, ce qui désactive les délais d'attente pour n'importe quelle requête. Vous pouvez également augmenter le paramètre lock_timeout . La valeur par défaut est 0, ce qui désactive les délais d'attente pour les verrous.

Résoudre les problèmes de création de l'emplacement

Si l'expiration s'est produite lorsque vous avez créé l'emplacement de réplication dans la base de données PostgreSQL, vous voyez des entrées de journal semblable à ce qui suit :

Messages

« ]E:  wal_slot_create(...) - Unable to create slot 'xxxxxxxxxxxxxxxx_00016391_c4a70947_84c9_4a55_8d54_ff63f2f69a52' (on execute(...) phase) [1020101]  (postgres_endpoint_wal_utils.c:3215) »

Si votre instance de réplication exécute la version 3.1.3 ou inférieure, le paramètre de délai d'exécution par défaut de 60 secondes est appliqué pour cette commande, qui remplace la valeur de executeTimeout. Pour résoudre ce problème, utilisez la version 3.1.4 pour laquelle le délai d'exécution par défaut pour cette commande est de 600 secondes. Vous pouvez augmenter ce délai en configurant le paramètre TransactionConsistencyTimeout dans la section Task settings (Paramètres de tâche).

PostgreSQL ne peut pas créer l'emplacement de réplication s'il y a des verrous actifs dans les tables d'utilisateur de base de données. Vérifiez les verrous en exécutant la commande suivante :

select * from pg_locks;

Ensuite, pour tester si l'erreur a été résolue, exécutez la commande suivante pour créer manuellement l'emplacement de réplication dans la base de données PostgreSQL source :

select  xlog_position FROM pg_create_logical_replication_slot('<Slot name as per
    the task log>', 'test_decoding');

Si la commande ne parvient toujours pas à créer l'emplacement, vous devrez peut-être utiliser un administrateur de base de données (DBA) PostgreSQL pour identifier le point de blocage et configurer votre base de données. Si la commande aboutit, supprimez l'emplacement que vous venez de créer comme test:

select pg_drop_replication_slot(‘<slot name>');

Enfin, redémarrez votre tâche de migration.