LWLock:SubtransSLRU (LWLock:SubtransControlLock)
LWLock:SubtransSLRU 및 LWLock:SubtransBuffer 대기 이벤트는 세션이 하위 트랜잭션 정보를 위해 가장 오래전에 사용된 단순(SLRU) 캐시에 액세스하기 위해 대기 중임을 나타냅니다. 이는 트랜잭션 가시성 및 상위-하위 관계를 결정할 때 발생합니다.
-
LWLock:SubtransSLRU: 프로세스가 하위 트랜잭션에 대해 가장 오래전에 사용된 단순(SLRU) 캐시에 액세스하기 위해 대기 중입니다. 버전 13 이전의 RDS for PostgreSQL에서는 이 대기 이벤트를SubtransControlLock이라고 합니다. -
LWLock:SubtransBuffer: 프로세스가 하위 트랜잭션에 대해 가장 오래전에 사용된 단순(SLRU) 버퍼에서 I/O를 기다리고 있습니다. 버전 13 이전의 RDS for PostgreSQL에서는 이 대기 이벤트를subtrans이라고 합니다.
지원되는 엔진 버전
이 대기 이벤트 정보는 모든 RDS for PostgreSQL 버전에서 지원됩니다.
컨텍스트
하위 트랜잭션 이해 - 하위 트랜잭션은 PostgreSQL의 트랜잭션 내 트랜잭션입니다. 이를 중첩 트랜잭션이라고도 합니다.
하위 트랜잭션은 일반적으로 다음을 사용할 때 생성됩니다.
-
SAVEPOINT명령 -
예외 블록(
BEGIN/EXCEPTION/END)
하위 트랜잭션을 사용하면 전체 트랜잭션에 영향을 주지 않고 트랜잭션의 일부를 롤백할 수 있습니다. 이를 통해 트랜잭션 관리를 세밀하게 제어할 수 있습니다.
구현 세부 정보 - PostgreSQL은 하위 트랜잭션을 기본 트랜잭션 내의 중첩 구조로 구현합니다. 각 하위 트랜잭션은 자체 트랜잭션 ID를 가져옵니다.
주요 구현 측면:
-
트랜잭션 ID는
pg_xact에서 추적됩니다. -
상위-하위 관계는
PGDATA아래의pg_subtrans하위 디렉터리에 저장됩니다. -
각 데이터베이스 세션은 최대
64개의 활성 하위 트랜잭션을 유지할 수 있습니다. -
이 제한을 초과하면 하위 트랜잭션 오버플로가 발생하므로 하위 트랜잭션 정보를 위해 가장 오래전에 사용된 단순(SLRU) 캐시에 액세스해야 합니다.
대기 증가의 가능한 원인
하위 트랜잭션 SLRU 경합의 일반적인 원인은 다음과 같습니다.
-
SAVEPOINT 및 EXCEPTION 처리의 과도한 사용 -
EXCEPTION핸들러가 있는 PL/pgSQL 프로시저는 예외 발생 여부에 관계없이 암시적 저장점을 자동으로 생성합니다. 각SAVEPOINT는 새 하위 트랜잭션을 시작합니다. 단일 트랜잭션에 64개 이상의 하위 트랜잭션이 누적되면 하위 트랜잭션 SLRU 오버플로가 트리거됩니다. -
드라이버 및 ORM 구성 -
SAVEPOINT는 애플리케이션 코드에서 명시적으로 사용하거나 드라이버 구성을 통해 암시적으로 사용할 수 있습니다. 일반적으로 사용되는 많은 ORM 도구 및 애플리케이션 프레임워크는 기본적으로 중첩된 트랜잭션을 지원합니다. 다음은 몇 가지 일반적인 예제입니다.-
JDBC 드라이버 파라미터
autosave는always또는conservative로 설정하면 각 쿼리 전에 저장점을 생성합니다. -
propagation_nested로 설정된 경우 Spring Framework 트랜잭션 정의입니다. -
requires_new: true가 설정된 경우의 Rails입니다. -
session.begin_nested가 사용되는 경우의 SQLAlchemy입니다. -
중첩
atomic()블록이 사용되는 경우의 Django입니다. -
Savepoint가 사용되는 경우의 GORM입니다. -
롤백 수준 설정이 문 수준 롤백으로 설정된 경우의 psqlODBC입니다(예:
PROTOCOL=7.4-2).
-
-
장기 실행 트랜잭션 및 하위 트랜잭션이 있는 높은 동시 워크로드 - 동시 워크로드가 많고 장기 실행 트랜잭션 및 하위 트랜잭션 중에 하위 트랜잭션 SLRU 오버플로가 발생하면 PostgreSQL의 경합이 증가합니다. 이는
LWLock:SubtransBuffer및LWLock:SubtransSLRU잠금에 대한 승격된 대기 이벤트로 표시됩니다.
작업
대기 이벤트의 원인에 따라 다른 작업을 권장합니다. 일부 작업은 즉각적인 완화를 제공하는 반면, 다른 작업은 조사 및 장기 수정이 필요합니다.
하위 트랜잭션 사용량 모니터링
PostgreSQL 버전 16.1 이상에서는 다음 쿼리를 사용하여 백엔드당 하위 트랜잭션 수 및 오버플로 상태를 모니터링합니다. 이 쿼리는 백엔드 통계를 활동 정보와 조인하여 하위 트랜잭션을 사용하는 프로세스를 보여 줍니다.
SELECT a.pid, usename, query, state, wait_event_type, wait_event, subxact_count, subxact_overflowed FROM (SELECT id, pg_stat_get_backend_pid(id) pid, subxact_count, subxact_overflowed FROM pg_stat_get_backend_idset() id JOIN LATERAL pg_stat_get_backend_subxact(id) AS s ON true ) a JOIN pg_stat_activity b ON a.pid = b.pid;
PostgreSQL 버전 13.3 이상에서는 pg_stat_slru 뷰에서 하위 트랜잭션 캐시 압력을 모니터링합니다. 다음 SQL 쿼리는 Subtrans 구성 요소에 대한 SLRU 캐시 통계를 검색합니다.
SELECT * FROM pg_stat_slru WHERE name = 'Subtrans';
blks_read 값이 지속적으로 증가하면 캐시되지 않은 하위 트랜잭션에 대한 디스크 액세스가 잦아 잠재적 SLRU 캐시 압력을 나타냅니다.
메모리 파라미터 구성
PostgreSQL 17.1 이상에서는 subtransaction_buffers 파라미터를 사용하여 하위 트랜잭션 SLRU 캐시 크기를 구성할 수 있습니다. 다음 구성 예제에서는 하위 트랜잭션 버퍼 파라미터를 설정하는 방법을 보여 줍니다.
subtransaction_buffers = 128
이 파라미터는 하위 트랜잭션 콘텐츠(pg_subtrans)를 캐싱하는 데 사용되는 공유 메모리의 양을 지정합니다. 단위 없이 지정하면 값은 일반적으로 각각 8KB인 BLCKSZ바이트 블록을 나타냅니다. 예를 들어, 값을 128로 설정하면 하위 트랜잭션 캐시에 1MB(128 * 8kB)의 메모리가 할당됩니다.
참고
모든 인스턴스가 일관되게 유지되도록 클러스터 수준에서 이 파라미터를 설정할 수 있습니다. 특정 워크로드 요구 사항 및 인스턴스 클래스에 적합하도록 값을 테스트하고 조정합니다. 파라미터 변경 사항을 적용하려면 인스턴스를 재부팅해야 합니다.
장기적인 조치
-
애플리케이션 코드 및 구성 검사 - 애플리케이션 코드 및 데이터베이스 드라이버 구성을 검토하여 일반적으로 명시적 및 암시적
SAVEPOINT사용량과 하위 트랜잭션 사용량을 모두 확인합니다. 64개 이상의 하위 트랜잭션을 생성할 가능성이 있는 트랜잭션을 식별합니다. -
저장점 사용량 감소 - 트랜잭션에서 저장점 사용을 최소화합니다.
-
EXCEPTION 블록을 사용하여 PL/pgSQL 프로시저 및 함수를 검토합니다. EXCEPTION 블록은 암시적 저장점을 자동으로 생성하여 하위 트랜잭션 오버플로에 기여할 수 있습니다. 각 EXCEPTION 절은 실행 중에 실제로 예외가 발생하는지 여부에 관계없이 하위 트랜잭션을 생성합니다.
예제 1: 문제가 있는 예외 블록 사용
다음 코드 예제는 여러 하위 트랜잭션을 생성하는 문제가 있는 EXCEPTION 블록 사용을 보여 줍니다.
CREATE OR REPLACE FUNCTION process_user_data() RETURNS void AS $$ DECLARE user_record RECORD; BEGIN FOR user_record IN SELECT * FROM users LOOP BEGIN -- This creates a subtransaction for each iteration INSERT INTO user_audit (user_id, action, timestamp) VALUES (user_record.id, 'processed', NOW()); UPDATE users SET last_processed = NOW() WHERE id = user_record.id; EXCEPTION WHEN unique_violation THEN -- Handle duplicate audit entries UPDATE user_audit SET timestamp = NOW() WHERE user_id = user_record.id AND action = 'processed'; END; END LOOP; END; $$ LANGUAGE plpgsql;다음은 예외 처리 대신 UPSERT를 사용하여 하위 트랜잭션 사용을 줄이는 개선된 코드 예제입니다.
CREATE OR REPLACE FUNCTION process_user_data() RETURNS void AS $$ DECLARE user_record RECORD; BEGIN FOR user_record IN SELECT * FROM users LOOP -- Use UPSERT to avoid exception handling INSERT INTO user_audit (user_id, action, timestamp) VALUES (user_record.id, 'processed', NOW()) ON CONFLICT (user_id, action) DO UPDATE SET timestamp = NOW(); UPDATE users SET last_processed = NOW() WHERE id = user_record.id; END LOOP; END; $$ LANGUAGE plpgsql;예제 2: STRICT 예외 핸들러
다음 코드 예제는 NO_DATA_FOUND를 사용한 문제가 있는 EXCEPTION 처리를 보여 줍니다.
CREATE OR REPLACE FUNCTION get_user_email(p_user_id INTEGER) RETURNS TEXT AS $$ DECLARE user_email TEXT; BEGIN BEGIN -- STRICT causes an exception if no rows or multiple rows found SELECT email INTO STRICT user_email FROM users WHERE id = p_user_id; RETURN user_email; EXCEPTION WHEN NO_DATA_FOUND THEN RETURN 'Email not found'; END; END; $$ LANGUAGE plpgsql;다음 향상된 코드 예제에서는 예외 처리 대신 IF NOT FOUND를 사용하여 하위 트랜잭션을 방지합니다.
CREATE OR REPLACE FUNCTION get_user_email(p_user_id INTEGER) RETURNS TEXT AS $$ DECLARE user_email TEXT; BEGIN SELECT email INTO user_email FROM users WHERE id = p_user_id; IF NOT FOUND THEN RETURN 'Email not found'; ELSE RETURN user_email; END IF; END; $$ LANGUAGE plpgsql; -
JDBC 드라이버 – 파라미터
autosave는always또는conservative로 설정하면 각 쿼리 전에 저장점을 생성합니다.never설정이 애플리케이션에 적합한지 평가합니다. -
PostgreSQL ODBC 드라이버(psqlODBC) - 롤백 수준 설정(문 수준 롤백용)은 암시적 저장점을 생성하여 문 롤백 기능을 활성화합니다. 트랜잭션 수준 롤백이 애플리케이션에 적합한지 여부를 평가합니다.
-
ORM 트랜잭션 구성 검사
-
저장점이 필요하지 않은 대체 오류 처리 전략 고려
-
-
트랜잭션 설계 최적화 - 트랜잭션을 재구성하여 과도한 중첩을 방지하고 하위 트랜잭션 오버플로 조건의 가능성을 줄입니다.
-
장기 실행 트랜잭션 감소 - 장기 실행 트랜잭션은 하위 트랜잭션 정보를 더 오래 보유하여 하위 트랜잭션 문제를 악화시킬 수 있습니다. Performance Insights 지표를 모니터링하고 유휴 트랜잭션을 자동으로 종료하도록
idle_in_transaction_session_timeout파라미터를 구성합니다. -
Performance Insights 지표 모니터링 -
idle_in_transaction_count(트랜잭션 상태에서 유휴 상태인 세션 수) 및idle_in_transaction_max_time(가장 오래 실행되는 유휴 트랜잭션 기간)을 포함한 지표를 추적하여 장기 실행 트랜잭션을 감지합니다. -
idle_in_transaction_session_timeout구성 - 지정된 기간 후에 유휴 트랜잭션을 자동으로 종료하도록 파라미터 그룹에서이 파라미터를 설정합니다. -
선제적 모니터링 -
LWLock:SubtransBuffer및LWLock:SubtransSLRU의 높은 발생을 모니터링하고 이벤트가 중요해지기 전에 하위 트랜잭션 관련 경합을 감지할 때까지 기다립니다.