PostgreSQL은 다른 데이터베이스 시스템들과 달리, 멀티 프로세스(Multi-Process) 구조를 사용합니다. 이 구조는 각 클라이언트 연결마다 독립적인 프로세스를 생성하여 데이터베이스 질의와 응답을 처리합니다.
이 방식은 격리성과 안정성을 보장하는데 탁월하지만, 오래 실행되는 쿼리(Long Query)로 인해 발생할 수 있는 몇 가지 문제가 있습니다.
특히, Autovacuum 프로세스가 이를 방해받아 제대로 동작하지 못할 수 있습니다. 이번 글에서는 PostgreSQL의 멀티 프로세스 구조가 왜 이러한 문제를 유발하는지, 그리고 이를 해결할 수 있는 다양한 방법에 대해 살펴보겠습니다.
멀티 프로세스 아키텍처에서 PostgreSQL은 각 클라이언트 연결마다 별도의 프로세스를 생성하는 방식을 사용합니다. 이러한 구조의 동작 방식은 다음과 같습니다.
이 구조의 장점으로는 격리성이 있습니다. 하나의 프로세스에서 문제가 발생해도 다른 프로세스에 영향을 미치지 않기 때문에 안정성이 높습니다. 하지만, 각 클라이언트 연결마다 별도의 프로세스가 생성되므로 리소스 사용량이 많아지고, 컨텍스트 스위칭 비용이 발생할 수 있다는 단점도 있습니다.
PostgreSQL은 MVCC(Multi-Version Concurrency Control)라는 동시성 제어 방식을 사용합니다. 트랜잭션이 데이터를 변경할 때 기존 데이터를 그대로 유지하고 새로운 데이터를 기록하여 동시성을 보장하는 방식입니다. 이 과정에서 데이터의 이전 버전, 즉 Old Tuple이 생성되며, 트랜잭션이 끝날 때까지 유지됩니다.
Autovacuum은 이러한 Old Tuple을 주기적으로 삭제하고, 테이블에 남아있는 불필요한 데이터를 정리하는 역할을 합니다. Autovacuum이 잘 동작해야만 데이터베이스의 디스크 공간을 효율적으로 사용할 수 있고, 성능 저하를 방지할 수 있습니다.
오래 실행되는 쿼리(Long Query)는 트랜잭션이 열려 있는 상태로 데이터를 계속해서 참조하게 만듭니다. 이로 인해 Autovacuum은 트랜잭션이 끝나지 않는 한, 해당 데이터에 대한 정리 작업을 수행하지 못하게 됩니다. 이러한 상태가 지속되면 디스크 공간을 과도하게 사용할 뿐만 아니라, 성능에도 악영향을 미칠 수 있습니다.
주요 문제
1) 트랜잭션을 짧게 유지
트랜잭션의 범위를 최소화하여 Long Query가 트랜잭션을 오래 잡아두지 않도록 개선하는 것이 가장 중요합니다.
2) Autovacuum 설정 최적화
Autovacuum 설정을 조정하면 더 자주 실행되도록 하거나 오래된 트랜잭션을 처리하는 빈도를 늘릴 수 있습니다.
예시 설정 (postgresql.conf)
autovacuum_vacuum_threshold = 50 # 더 자주 Autovacuum 실행
autovacuum_freeze_max_age = 100000000 # 트랜잭션 처리 주기 조정
vacuum_cost_delay = 10ms # 자원 소비 줄이기 위한 지연 설정
3) 수동 VACUUM 실행
Autovacuum이 제대로 동작하지 않는 경우, Long Query가 종료된 후 수동으로 VACUUM을 실행하여 데이터 정리를 할 수 있습니다.
VACUUM ANALYZE;
또는 디스크 공간을 회수해야 한다면, VACUUM FULL 명령을 사용할 수 있지만, 테이블이 독점 잠금(Lock) 상태가 되므로 신중히 사용해야 합니다.
4) Long Query 모니터링 및 최적화
Long Query는 PostgreSQL의 pg_stat_activity 뷰를 통해 모니터링할 수 있으며, 이를 기반으로 성능을 최적화해야 합니다.
Long Query 모니터링 쿼리
SELECT pid, usename, query, state, age(clock_timestamp(), query_start) AS runtime
FROM pg_stat_activity
WHERE state != 'idle' AND query != '<IDLE>' AND age(clock_timestamp(), query_start) > interval '5 minutes';
5) Statement Timeout 설정
Long Query를 강제로 제한하려면 쿼리 타임아웃을 설정할 수 있습니다. 일정 시간 동안 실행되지 않으면 쿼리를 중단하도록 설정하여 Autovacuum 작업에 방해가 되지 않도록 합니다.
예시 설정 (postgresql.conf)
statement_timeout = '5min'; # 5분 이상 실행되는 쿼리는 자동으로 중단
6) 모니터링 및 도구 활용
Autovacuum이 제대로 동작하는지 확인하기 위해 pg_stat_user_tables를 활용해 마지막으로 Autovacuum이 실행된 시점을 확인할 수 있습니다.
-- Autovacuum 실행 시점 확인
SELECT relname, last_autovacuum, last_vacuum
FROM pg_stat_user_tables
WHERE last_autovacuum IS NOT NULL OR last_vacuum IS NOT NULL;
또한 pgAdmin이나 Percona Monitoring and Management(PMM)와 같은 외부 모니터링 도구를 통해 PostgreSQL의 성능 및 Autovacuum 동작을 시각적으로 모니터링할 수 있습니다.
PostgreSQL의 멀티 프로세스 구조는 뛰어난 안정성을 제공하지만, Long Query로 인한 Autovacuum 문제는 성능에 큰 영향을 미칠 수 있습니다. 이를 해결하기 위해서는 트랜잭션을 짧게 유지하고, Autovacuum 설정을 최적화하며, Long Query를 모니터링하고 최적화하는 것이 중요합니다. 또한 수동으로 VACUUM을 실행하거나 쿼리 타임아웃을 설정하는 등의 방안도 고려할 수 있습니다.
이를 통해 PostgreSQL의 안정성과 성능을 극대화하면서도 시스템 자원을 효율적으로 관리할 수 있습니다.