Comment puis-je 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)?

Date de la dernière mise à jour: 30/09/2019

Je migre des données vers ma base de données PostgreSQL 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 puis-je 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 source 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: RetCode: SQL_ERROR SqlState: 57014 NativeError: 1 Message: ERROR : canceling statement due to statement timeout; « ] E: RetCode: SQL_ERROR SqlState: 57014 NativeError: 1 Message: ERREUR : annulation de l'instruction en raison de l'expiration de son délai d'exécution; »

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

Identifier 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 SÉLECTION 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 »(METTRE À JOUR) ce qui prend beaucoup de temps.

Augmenter 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 volet de navigation.

3.    Choisissez le point de terminaison PostgreSQL.

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

5.    Agrandissez 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.    Sélectionnez Save (Enregistrer).

8.    Dans le volet « 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 » (Abouti).

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.