Lock:tuple - Amazon Relational Database Service

Lock:tuple

Lock:tuple 이벤트는 백엔드 프로세스가 튜플에 대한 잠금 획득을 대기 중일 때 발생합니다.

지원되는 엔진 버전

이 대기 이벤트 정보는 모든 RDS for PostgreSQL 버전에서 지원됩니다.

컨텍스트

이벤트 Lock:tuple은 다른 백엔드가 동일한 튜플에서 충돌하는 잠금을 보유하는 동안 백엔드가 튜플에 대한 잠금을 얻기 위해 대기 중임을 나타냅니다. 다음 테이블에서는 세션이 Lock:tuple 이벤트를 생성하는 시나리오를 가정합니다.

시간

세션 1

세션 2

세션 3

t1

트랜잭션을 시작합니다.

t2

1행을 업데이트합니다.

t3

1행을 업데이트합니다. 세션은 튜플에 대한 배타적 잠금을 획득한 다음 세션 1이 커밋하거나 롤백하여 잠금을 해제할 때까지 기다립니다.

t4

1행을 업데이트합니다. 세션은 세션 2가 튜플에서 배타적 잠금을 해제할 때까지 기다립니다.

또는 벤치마킹 도구 pgbench를 사용하여 이 대기 이벤트를 시뮬레이션할 수 있습니다. 테이블의 동일한 행을 사용자 정의 SQL 파일로 업데이트하도록 많은 수의 동시 세션을 구성합니다.

충돌하는 잠금 모드에 대한 자세한 내용은 PostgreSQL 설명서의 명시적 잠금을 참조하세요. pgbench에 관한 더 자세한 내용은 PostgreSQL 설명서의 pgbench 섹션을 참조하세요.

대기 증가의 가능한 원인

이 이벤트가 정상보다 많이 발생해 성능 문제를 일으킬 수 있는 경우 일반적인 원인은 다음과 같습니다.

  • 많은 수의 동시 세션이 UPDATE 또는 DELETE 문을 실행하여 동일한 튜플에 대해 충돌하는 잠금을 얻으려고 시도합니다.

  • 높은 동시 세션이 FOR UPDATE 또는 FOR NO KEY UPDATE 잠금 모드를 통해 SELECT 문을 실행하고 있습니다.

  • 다양한 요인으로 인해 애플리케이션이나 연결 풀이 더 많은 세션을 열어 동일한 작업을 실행할 수 있습니다. 새 세션이 동일한 행을 수정하려고 하면 DB 로드가 급증할 수 있으며, Lock:tuple이 표시될 수 있습니다.

자세한 내용은 PostgreSQL 설명서의 행 수준 잠금을 참조하세요.

작업

대기 이벤트의 원인에 따라 다른 작업을 권장합니다.

애플리케이션 로직 조사

차단 세션이 오랜 시간 동안 idle in transaction 상태인지 확인하세요. 그렇다면 차단 세션을 단기 솔루션으로 종료하는 것이 좋습니다. pg_terminate_backend 함수를 사용할 수 있습니다. 이 함수에 대한 자세한 내용은 PostgreSQL 설명서의 서버 신호 전송 함수를 참조하세요.

장기 솔루션의 경우 다음을 수행합니다.

  • 애플리케이션 로직을 조정합니다.

  • idle_in_transaction_session_timeout 파라미터를 사용합니다. 이 파라미터는 지정된 시간보다 오랫동안 유휴 상태인 열린 트랜잭션으로 세션을 종료합니다. 자세한 내용은 PostgreSQL 설명서의 클라이언트 인증을 참조하세요.

  • autocommit을 최대한 많이 사용합니다. 자세한 내용은 PostgreSQL 설명서의 AUTOCOMMIT 설정을 참조하세요.

차단 세션 찾기

Lock:tuple 대기 이벤트가 발생하는 동안 어떤 잠금이 서로 의존하는지 파악하여 차단 및 차단된 세션을 식별합니다. 자세한 내용은 PostgreSQL 위키의 잠금 종속성 정보를 참조하세요.

다음 예에서는 tuple 필터링과 wait_time 정렬을 통해 모든 세션을 쿼리합니다.

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;

높은 동시성 저감

Lock:tuple 이벤트는 지속적으로 발생할 수 있으며, 특히 작업 부하가 많은 시간에 발생할 수 있습니다. 이 경우 매우 바쁜 행에 대해 높은 동시성을 줄이는 것이 좋습니다. 종종 몇 개의 행만 대기열이나 불리언 로직을 제어하므로 이러한 행을 매우 바쁘게 만듭니다.

비즈니스 요구 사항, 애플리케이션 로직 및 워크로드 유형에 따라 다양한 접근 방식을 사용하여 동시성을 줄일 수 있습니다. 예를 들면, 다음을 수행할 수 있습니다.

  • 테이블 및 데이터 로직을 재설계하여 높은 동시성을 줄입니다.

  • 행 수준에서 높은 동시성을 줄이기 위해 애플리케이션 로직을 변경합니다.

  • 행 수준 잠금으로 쿼리를 활용하고 재설계합니다.

  • NOWAIT 절을 사용해 연산을 재시도합니다.

  • 낙관적 및 하이브리드 잠금 로직 동시성 제어를 사용하는 것이 좋습니다.

  • 데이터베이스 격리 수준을 변경하는 것이 좋습니다.

병목 현상 해결

Lock:tuple은 CPU 부족 또는 Amazon EBS 대역폭의 최대 사용량과 같은 병목 현상이 발생시킬 수 있습니다. 병목 현상을 줄이려면 다음 방법을 고려하세요.

  • 인스턴스 클래스 유형을 확장하세요.

  • 리소스 집약적인 쿼리를 최적화하세요.

  • 애플리케이션 로직을 변경하세요.

  • 거의 액세스하지 않는 데이터를 아카이브하세요.