이전까지 PostgreSQL Replication 관련 Wait Event를 알아보았습니다.
이번에는 ProcArray, MultiXacxt, SubXact와 같은 PostgreSQL의 트랜잭션 관리 메커니즘에 대해 알아보고 이와 관련된 Wait Event를 설명하겠습니다.
이를 위해 본 문서에서는 먼저 ProcArray의 개념과 동작 원리에 대해 살펴 본 후, 관련 Wait Event에 대해 다룹니다.
ProcArray
PostgreSQL은 Session과 트랜잭션 상태를 관리하기 위해 ProcArray를 사용합니다.
ProcArray는 전체 Session과 트랜잭션 상태를 전역적으로 관리하는 모듈로, Tuple 가시성 판단, VACUUM horizon 계산, Replication Conflict 처리 등 다양한 기능을 수행합니다. 이러한 다양한 동작을 위해 이 모듈은 Shared Memory에 저장된 여러 프로세스 상태 정보를 참조합니다.
주요 구성 요소
ProcArray 모듈은 Shared Memory에 위치한 ProcGlobal에 저장된 정보를 기반으로 동작합니다.
ProcGlobal에는 Session과 관련된 모든 트랜잭션 상태가 저장되어 있으며, ProcArray는 이 정보를 기반으로 현재 활성화된 Session과 트랜잭션 상태를 관리합니다. 또한 Session들은 해당 정보를 참조하여 서로 간의 상태를 확인할 수 있습니다.
ProcGlobal을 구성하는 주요 구성 요소는 다음과 같습니다.

PGPROC
트랜잭션 식별 정보(xid,xmin), 프로세스 PID, Database OID, Lock 대기 정보 등이 저장되어 있으며 Session마다 하나씩 할당되는 배열 요소입니다. 각 PGPROC은 고유한 인덱스(pgprocno)를 가지고 있어 위치가 식별됩니다.
allProcs
PGPROC을 개별 요소로 갖는 배열이며 모든 Session에 대한 정보를 저장합니다. PGPROC에 저장된 pgprocno는 allprocs 내에서의 위치를 의미합니다.
Dense Array (PostgreSQL 14 이후)
PostgreSQL 14 이후 생성된 배열 구조로, PGPROC 정보 중 자주 Access 되는 정보들만 미러링하여 모아둔, 경량화된 배열입니다. 모든 Session에 대한 정보를 가진 allProcs와 다르게 Active Session의 정보만 연속적으로 저장합니다.
ProcArray 동작 과정
Query를 수행할 때는 해당 시점에 읽을 수 있는 Tuple을 식별하기 위해 Snapshot이 필요합니다. Snapshot에는 Query 수행 시점의 트랜잭션 정보(xid, xmin 등)가 저장되며, 이 정보는 이후 Tuple의 가시성을 판단하는 데 사용됩니다.
이때 ProcArray 모듈이 내부 함수를 호출하여 Snapshot을 생성하는 역할을 담당합니다. ProcArray 모듈이 Snapshot을 생성하는 과정을 간단히 표현하면 다음과 같습니다.

- 사용자 프로세스 내의 트랜잭션에서 Query를 수행하면 Tuple 가시성 판단을 위해 Snapshot 생성 작업이 요청됩니다.
- 사용자 프로세스는 ProcArray Lock을 획득합니다.
ProcArrayLock
ProcArray Lock은 ProcArray 모듈 동작을 위해 프로세스가 획득해야 하는 LWLock입니다.
모듈 동작에 사용되는 ProcGlobal은 Shared Memory에 위치해 있으므로 프로세스 간의 경합을 관리하기 위해 해당 Lock이 사용됩니다.
- ProcArray 모듈 함수가 호출되어 ProcGlobal 내부의 Dense Array가 Scan됩니다. 이 과정에서 다음의 정보가 수집된 후 Snapshot에 저장됩니다.
- Active 트랜잭션의 xid
- 각 프로세스의 xmin
- 새로 할당할 수 있는 xmax 값
필요한 정보가 모두 저장되면 프로세스는 ProcArray Lock을 해제합니다.
- 사용자 프로세스는 각 Tuple Header 정보(xmin,xmax)와 Snapshot 정보를 비교하여 읽기 가능한(visible) Tuple만 읽어 Query를 처리합니다.
PostgreSQL 13 이전 버전에서는 Snapshot 생성 시 allProcs 배열 전체를 스캔해야 했습니다.
이 배열에는 Active 상태가 아닌 프로세스 정보까지 포함되어 있어 그만큼 ProcArrayLock을 오래 유지해야 했습니다. PostgreSQL 14부터는 Active Session 정보만 저장된 Dense Array 구조가 도입됨에 따라 스캔 범위가 줄어 ProcArrayLock 경합이 크게 감소했습니다
Wait Event
이번에는 ProcArray 모듈 동작 과정에서 발생할 수 있는 대표적인 Wait Event인 LWLock:ProcArray와 IPC:ProcArrayGroupUpdate에 대해서 알아보겠습니다.
LWLock:ProcArray
LWLock:ProcArray는 ProcArray Lock 획득을 대기할 때 발생하는 Wait Event로, 해당 Lock은 ProcArray 모듈에 대한 동작을 요청할때 필요로 합니다. 주로 여러 프로세스가 동시에 Snapshot 생성이나 Session XID 확인을 요청할 때 발생하며 이 경우 먼저 ProcArray Lock을 획득한 프로세스가 작업을 완료할 때까지 대기합니다.
주요 발생 원인
- Snapshot 생성 빈도가 높거나, 동시 트랜잭션이 많을 때
- 짧은 Query가 빠르게 반복 실행되면 매번 새로운 Snapshot을 생성해야 합니다. 결과적으로 ProcArray Lock 획득 빈도가 증가하여 대기 상황에 노출될 위험이 높아집니다.
- 동시 트랜잭션이 많을수록 Snapshot 생성 시 확인해야 할 정보가 증가합니다. 이에 따라 ProcArray Access 시간이 늘어나므로 Wait Event 발생 빈도가 높아질 수 있습니다.
- Vacuum이 자주 수행될 때
- Vacuum은 가장 오래된 xmin(xmin horizon)을 확인하기 위해 ProcArray에 Access 하며, 이 과정에서 모든 Active Session의 xmin을 확인합니다. 따라서 Active Session 수가 많을수록 Access 시간이 증가하여 Wait Event 발생이 증가할 수 있습니다.
해결 방안
- Session 관리 최적화
- 동시 트랜잭션을 제한하기 위해 Connection Pool 등을 통한 Session 수를 관리하면, Lock 경합 및 ProcArray Access 시간을 감소시킬 수 있습니다.
- 불필요하게 자주 실행되는 짧은 Query를 배치 처리하거나 통합하여 Snapshot 생성 빈도를 줄입니다.
idle in transaction상태의 Session은 Active Session 수를 증가시켜 ProcArray Scan 범위를 늘리고 Vacuum 효율도 저하 시킵니다. idle_in_transaction_session_timeout 파라미터를 설정하여 장시간 대기 중인 트랜잭션을 자동으로 종료합니다.- Autovacuum 파라미터(autovacuum_naptime, autovacuum_vacuum_threshold 등)를 조정하여 과도한 Vacuum 실행을 방지합니다.
IPC:ProcArrayGroupUpdate
PostgreSQL은 OLTP 환경에서 Commit 성능을 높이기 위해 여러 트랜잭션을 묶어 처리합니다(Group Commit). 이때 일부 트랜잭션이 리더 역할을 맡아 그룹 전체의 Commit을 수행하며, 나머지 트랜잭션들은 이 작업이 완료될 때까지 대기합니다.
IPC:ProcArrayGroupUpdate는 이러한 Group Commit 과정에서 리더 트랜잭션이 ProcGlobal 배열의 트랜잭션 상태를 갱신하는 동안 다른 트랜잭션들이 대기할 때 발생하는 Wait Event입니다. 이 Wait Event는 PostgreSQL 14 이후 추가되었으며, 정상적인 최적화 동작에 의해 발생하므로 문제 상황으로 보기보다는 Commit 패턴과 Workload 특성을 파악하는 지표로 활용할 수 있습니다.
마무리
- ProcArray는 전체 Session과 트랜잭션 상태를 전역적으로 관리하는 모듈로, ProcGlobal의 정보를 기반으로 동작한다. PostgreSQL 14부터는 Active Session 정보만 저장하는 Dense Array 구조가 도입되어 성능이 개선되었다.
- ProcArray Lock은 ProcArray 모듈이 동작하기 위해 획득해야 하는 LWLock이다. 여러 프로세스가 동시에 Snapshot을 생성하거나 트랜잭션 상태를 확인할 때 이 Lock을 획득해야 하므로, 동시성이 높은 환경에서는 경합이 발생할 수 있다.
- LWLock:ProcArray는 ProcArray Lock 획득 과정에서 경합 발생시 나타나는 Wait Event이다. 높은 동시 트랜잭션 수 혹은 잦은 Vacuum 수행이 주요 원인이며, Connection Pool 사용,
idle in transaction Session관리 등을 통해 경합을 줄일 수 있다.
- IPC:ProcArrayGroupUpdate는 Group Commit 과정에서 발생하는 정상적인 최적화 동작으로, 리더 트랜잭션이 그룹 전체의 Commit을 처리하는 동안 다른 트랜잭션들이 대기할 때 발생한다.
함께 보면 좋은 아티클
