PostgreSQL의 멀티 프로세스 구조와 Autovacuum 문제 해결

이세현·2024년 9월 19일
0

PostgreSQL for DBA

목록 보기
12/19

PostgreSQL의 멀티 프로세스 구조와 Autovacuum 문제 해결

PostgreSQL은 다른 데이터베이스 시스템들과 달리, 멀티 프로세스(Multi-Process) 구조를 사용합니다. 이 구조는 각 클라이언트 연결마다 독립적인 프로세스를 생성하여 데이터베이스 질의와 응답을 처리합니다.

이 방식은 격리성과 안정성을 보장하는데 탁월하지만, 오래 실행되는 쿼리(Long Query)로 인해 발생할 수 있는 몇 가지 문제가 있습니다.

특히, Autovacuum 프로세스가 이를 방해받아 제대로 동작하지 못할 수 있습니다. 이번 글에서는 PostgreSQL의 멀티 프로세스 구조가 왜 이러한 문제를 유발하는지, 그리고 이를 해결할 수 있는 다양한 방법에 대해 살펴보겠습니다.

1. PostgreSQL의 멀티 프로세스 구조

멀티 프로세스 아키텍처에서 PostgreSQL은 각 클라이언트 연결마다 별도의 프로세스를 생성하는 방식을 사용합니다. 이러한 구조의 동작 방식은 다음과 같습니다.

  • 메인 프로세스(Postmaster): PostgreSQL 서버를 시작하면 메인 프로세스가 실행되며, 클라이언트 연결을 관리합니다.
  • 클라이언트 연결: 클라이언트가 데이터베이스에 연결할 때마다 새로운 프로세스를 포크(fork)하여 해당 클라이언트를 위한 독립적인 프로세스를 생성합니다. 이 프로세스는 클라이언트의 질의와 응답을 처리합니다.
  • 백그라운드 프로세스: 체크포인트 관리, 로그 쓰기, autovacuum 등의 작업을 처리하기 위한 백그라운드 프로세스들이 별도로 실행됩니다.

이 구조의 장점으로는 격리성이 있습니다. 하나의 프로세스에서 문제가 발생해도 다른 프로세스에 영향을 미치지 않기 때문에 안정성이 높습니다. 하지만, 각 클라이언트 연결마다 별도의 프로세스가 생성되므로 리소스 사용량이 많아지고, 컨텍스트 스위칭 비용이 발생할 수 있다는 단점도 있습니다.

2. Autovacuum과 MVCC

PostgreSQL은 MVCC(Multi-Version Concurrency Control)라는 동시성 제어 방식을 사용합니다. 트랜잭션이 데이터를 변경할 때 기존 데이터를 그대로 유지하고 새로운 데이터를 기록하여 동시성을 보장하는 방식입니다. 이 과정에서 데이터의 이전 버전, 즉 Old Tuple이 생성되며, 트랜잭션이 끝날 때까지 유지됩니다.

Autovacuum은 이러한 Old Tuple을 주기적으로 삭제하고, 테이블에 남아있는 불필요한 데이터를 정리하는 역할을 합니다. Autovacuum이 잘 동작해야만 데이터베이스의 디스크 공간을 효율적으로 사용할 수 있고, 성능 저하를 방지할 수 있습니다.

3. Long Query가 Autovacuum에 미치는 영향

오래 실행되는 쿼리(Long Query)는 트랜잭션이 열려 있는 상태로 데이터를 계속해서 참조하게 만듭니다. 이로 인해 Autovacuum은 트랜잭션이 끝나지 않는 한, 해당 데이터에 대한 정리 작업을 수행하지 못하게 됩니다. 이러한 상태가 지속되면 디스크 공간을 과도하게 사용할 뿐만 아니라, 성능에도 악영향을 미칠 수 있습니다.

주요 문제

  • Old Tuple 유지: Long Query가 열려 있는 동안, Autovacuum은 데이터를 삭제하지 못해 디스크 공간이 계속 증가합니다.
  • 트랜잭션 ID 랩어라운드 문제(Transaction ID Wraparound): PostgreSQL의 트랜잭션 ID가 한계를 넘으면 Wraparound 현상이 발생하여 데이터베이스의 일관성에 문제가 생길 수 있습니다. 이를 방지하려면 Autovacuum이 제때 실행되어야 합니다.

4. 문제 해결 방안

1) 트랜잭션을 짧게 유지

트랜잭션의 범위를 최소화하여 Long Query가 트랜잭션을 오래 잡아두지 않도록 개선하는 것이 가장 중요합니다.

  • 쿼리 범위 최소화: 트랜잭션 내에서 불필요한 작업을 줄이고, 필요한 경우 즉시 커밋(commit)하거나 롤백(rollback)합니다.
  • 배치 처리: 대량의 데이터를 처리해야 한다면, 이를 작은 트랜잭션으로 나누어 처리합니다.
  • 백그라운드 작업 처리: 긴 쿼리를 별도의 백그라운드 작업으로 분리하여 처리하는 것도 방법입니다.

2) Autovacuum 설정 최적화
Autovacuum 설정을 조정하면 더 자주 실행되도록 하거나 오래된 트랜잭션을 처리하는 빈도를 늘릴 수 있습니다.

  • autovacuum_vacuum_threshold: 테이블의 튜플 중 일정 비율이 변경되면 Autovacuum이 실행되도록 설정합니다.
  • autovacuum_freeze_max_age: 오래된 트랜잭션을 처리하는 주기를 조정해 XID 랩어라운드를 방지할 수 있습니다.
  • vacuum_cost_delay: 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';
  • 쿼리 리팩토링: 복잡한 쿼리는 쪼개서 성능을 최적화할 수 있습니다.
  • 인덱스 추가: 빈번하게 사용되는 조건에 인덱스를 추가하여 쿼리 성능을 높입니다.
  • 실행 계획 분석: EXPLAIN을 사용해 쿼리의 실행 계획을 분석하고 최적화 포인트를 찾습니다.

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의 안정성과 성능을 극대화하면서도 시스템 자원을 효율적으로 관리할 수 있습니다.

profile
pglover_12

0개의 댓글