Lock:advisory - Amazon Relational Database Service

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Lock:advisory

L'événement Lock:advisory se produit lorsqu'une application PostgreSQL utilise un verrou pour coordonner l'activité sur plusieurs sessions.

Versions de moteur pertinentes

Ces informations sur les événements d'attente s'appliquent à RDS for PostgreSQL 9.6 et versions ultérieures.

Contexte

Les verrous consultatifs PostgreSQL sont des verrous coopératifs de niveau application explicitement verrouillés et déverrouillés par le code d'application de l'utilisateur. Une application peut utiliser des verrous consultatifs PostgreSQL pour coordonner l'activité sur plusieurs sessions. Contrairement aux verrous standard, de niveau objet ou ligne, l'application dispose d'un contrôle total sur la durée de vie du verrou. Pour en savoir plus, consultez Advisory Locks dans la documentation PostgreSQL.

Les verrous consultatifs peuvent être libérés avant la fin d'une transaction ou être maintenus par une session sur plusieurs transactions. Cela ne s'applique pas aux verrous implicites appliqués par le système, comme un verrou exclusif d'accès à une table acquis par une instruction CREATE INDEX.

Pour accéder à la description des fonctions utilisées pour acquérir (verrouiller) et libérer (déverrouiller) les verrous consultatifs, consultez Advisory Lock Functions dans la documentation PostgreSQL.

Les verrous consultatifs sont implémentés au-dessus du système de verrouillage PostgreSQL standard et sont visibles dans la vue système pg_locks.

Causes

Ce type de verrou est exclusivement contrôlé par une application qui l'utilise explicitement. Les verrous consultatifs qui sont acquis pour chaque ligne dans le cadre d'une requête peuvent provoquer un pic de verrous ou une accumulation à long terme.

Ces effets se produisent lorsque la requête est exécutée d'une manière qui acquiert des verrous sur plus de lignes que celles renvoyées par la requête. L'application doit finir par libérer chaque verrou, mais si des verrous sont acquis sur des lignes qui ne sont pas renvoyées, l'application ne peut pas tous les trouver.

L'exemple suivant est extrait de la section Advisory Locks de la documentation PostgreSQL.

SELECT pg_advisory_lock(id) FROM foo WHERE id > 12345 LIMIT 100;

Dans cet exemple, la clause LIMIT ne peut arrêter la sortie de la requête que lorsque les lignes ont déjà été sélectionnées en interne et que leurs valeurs d'ID ont été verrouillées. Cela peut se produire soudainement lorsqu'un volume de données croissant amène le planificateur à choisir un plan d'exécution différent qui n'a pas été testé lors de la phase de développement. Dans ce cas, l'accumulation se produit parce que l'application appelle explicitement pg_advisory_unlock pour chaque valeur d'ID verrouillée. Mais elle ne trouve pas l'ensemble de verrous acquis sur les lignes qui n'ont pas été renvoyées. Comme les verrous sont acquis au niveau de la session, ils ne sont pas libérés automatiquement à la fin de la transaction.

Les pics de tentatives de verrouillage bloquées peuvent également être liés à des conflits involontaires. Lors de ces conflits, des parties non liées de l'application partagent par erreur le même espace d'ID de verrou.

Actions

Examinez la façon dont les verrous consultatifs sont utilisés par l'application et indiquez où et quand, dans le flux d'application, chaque type de verrou consultatif est acquis et libéré.

Déterminez si une session acquiert trop de verrous ou si une session longue ne libère pas les verrous suffisamment tôt, ce qui entraîne une accumulation lente des verrous. Vous pouvez corriger une accumulation lente de verrous au niveau de la session en mettant fin à la session à l'aide de pg_terminate_backend(pid).

Un client en attente d'un verrou consultatif apparaît dans pg_stat_activity avec wait_event_type=Lock et wait_event=advisory. Vous pouvez obtenir des valeurs de verrouillage spécifiques en interrogeant la vue système pg_locks sur le même pid, à la recherche de locktype=advisory et granted=f.

Vous pouvez ensuite identifier la session de blocage en interrogeant pg_locks sur le même verrou consultatif doté de granted=t, comme illustré dans l'exemple suivant.

SELECT blocked_locks.pid AS blocked_pid, blocking_locks.pid AS blocking_pid, blocked_activity.usename AS blocked_user, blocking_activity.usename AS blocking_user, now() - blocked_activity.xact_start AS blocked_transaction_duration, now() - blocking_activity.xact_start AS blocking_transaction_duration, concat(blocked_activity.wait_event_type,':',blocked_activity.wait_event) AS blocked_wait_event, concat(blocking_activity.wait_event_type,':',blocking_activity.wait_event) AS blocking_wait_event, blocked_activity.state AS blocked_state, blocking_activity.state AS blocking_state, blocked_locks.locktype AS blocked_locktype, blocking_locks.locktype AS blocking_locktype, blocked_activity.query AS blocked_statement, blocking_activity.query AS blocking_statement 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;

Toutes les fonctions d'API des verrous consultatifs comportent deux ensembles d'arguments, soit un argument bigint, soit deux arguments integer :

  • Pour les fonctions d'API comportant un argument bigint, les 32 bits supérieurs figurent dans pg_locks.classid et les 32 bits inférieurs se trouvent dans pg_locks.objid.

  • Pour les fonctions d'API comportant deux arguments integer, le premier argument est pg_locks.classid et le deuxième est pg_locks.objid.

La valeur pg_locks.objsubid indique quelle forme d'API a été utilisée : 1 pour un argument bigint et 2 pour deux arguments integer.