Back to blog

버그의 여정: 고객 문제 제기에서 PostgreSQL 커밋까지

August 10, 2026

딜립 쿠마르 작성 | 2024년 5월 9일

소프트웨어 개발에서 버그는 애플리케이션과 시스템의 안정적인 운영을 방해합니다. 그러나 고객의 문제 제기로 시작된 버그 분석은 조사와 임시 해결책을 거쳐 소프트웨어 생태계 전반을 개선하는 계기가 되기도 합니다.

이 글에서는 은행 서비스에서 발견된 PostgreSQL 서브트랜잭션 성능 문제를 추적하고, 고객 전용 핫픽스를 제공한 뒤 PostgreSQL 오픈 소스 커밋으로 발전시킨 과정을 살펴봅니다. 또한 SubtransSLRUSubtransBuffer 대기 이벤트의 원인, SLRU 캐시 오버플로우 및 수정 후 성능 테스트 결과를 설명합니다.


1. PostgreSQL 버그의 시작: 고객 문제 제기

버그의 여정은 은행 서비스의 데이터베이스 서버에 과도한 부하가 발생해 안정성이 위협받는다는 지원 티켓에서 시작되었습니다. 지원팀과 고객이 함께 상황을 확인한 결과, 서버가 과부하로 인해 새로운 연결을 수락하지 못하고 있었습니다.


2. PostgreSQL 대기 이벤트 발견 및 보고

PostgreSQL 개발자로서 첫 단계는 시스템이 대부분의 시간을 소비하는 대기 이벤트를 식별하는 것이었습니다. 다음 쿼리로 대기 이벤트를 집계한 결과, 대부분의 시간이 SubtransSLRUSubtransBuffer 대기 이벤트에서 소비되고 있음을 발견했습니다.

\t
SELECT wait_event_type, wait_event 
FROM pg_stat_activity 
WHERE pid != pg_backend_pid()
\watch 0.5

집계 결과는 다음과 같습니다.

CountWait Event TypeWait Event
86595LWLockSubtransSLRU
14619LWLockSubtransBuffer
2574ClientClientRead
1876ActivityWalWriterMain
823  
404IOSLRURead

wait_event는 대기 없이 CPU에서 실제 작업이 수행되고 있음을 의미합니다. 결과를 보면 시스템이 SubtransSLRUSubtransBuffer 대기 이벤트에서 100배 더 많은 시간을 소비하고 있음을 확인할 수 있습니다.


3. SubtransSLRU와 SubtransBuffer 원인 분석

PostgreSQL에서 SubtransSLRUSubtransBuffer 대기 이벤트는 일반적으로 pg_subtrans SLRU 서브시스템에 과도한 부하가 걸린 경우 발생합니다. 단순 최소 최근 사용(Simple Least Recently Used, SLRU) 캐시는 PostgreSQL 운영에 중요한 여러 트랜잭션 관련 정보를 저장하는 디스크 페이지 기반 메커니즘입니다.

PostgreSQL 가시성과 트랜잭션 스냅샷

문제를 자세히 이해하려면 PostgreSQL의 가시성 개념과 대기 이벤트의 관계를 알아야 합니다. 튜플 또는 행 버전의 가시성은 xminxmax 시스템 열에 의해 결정되며, 각 열에는 생성 트랜잭션과 삭제 트랜잭션의 트랜잭션 ID가 저장됩니다.

쿼리가 시작되면 PostgreSQL은 해당 쿼리 실행 중 적용할 가시성 규칙을 결정하는 스냅샷을 생성합니다. 이 스냅샷에는 동시 트랜잭션과 서브트랜잭션의 배열이 포함됩니다.

64개를 초과하는 서브트랜잭션과 캐시 오버플로우

PostgreSQL은 먼저 공유 데이터 구조를 검사하고 각 세션의 트랜잭션 ID를 읽어 스냅샷을 준비합니다. 하나의 트랜잭션 아래에 여러 서브트랜잭션이 존재할 수 있으므로, PostgreSQL은 각 최상위 트랜잭션당 64개의 서브트랜잭션으로 캐시를 제한합니다.

하나의 트랜잭션에서 64개를 초과하는 서브트랜잭션을 생성하면 캐시가 오버플로우합니다. 이에 따라 동시 스냅샷은 완전한 정보를 포함하지 못하고 오버플로우 상태로 표시됩니다.

행에서 트랜잭션의 가시성을 확인할 때 PostgreSQL은 먼저 최상위 트랜잭션 ID를 검색하며, 이 과정에는 SLRU 캐시 접근이 필요합니다. 오버플로우된 스냅샷이 증가하면 동시 백엔드들이 SLRU 캐시 접근을 두고 경쟁하면서 SubtransSLRU 잠금과 관련된 대기 이벤트가 발생합니다.

장기 실행 트랜잭션과 SubtransBuffer 대기

장기 실행 트랜잭션이 있으면 PostgreSQL은 최신 서브트랜잭션뿐 아니라 이전 서브트랜잭션의 부모 정보도 가져와야 합니다. 이에 따라 xid 조회 범위가 확장되고 SLRU 캐시의 부담이 증가합니다. 그 결과, 디스크 페이지 로드와 디스크 I/O 작업이 빈번해지면서 SubtransBuffer 대기 이벤트가 발생합니다.

고객 환경에서 서브트랜잭션 오버플로우의 존재는 분명했지만, 문제를 일으킨 애플리케이션의 특정 부분을 찾기는 어려웠습니다. 오버플로우의 성능 영향이 이를 발생시킨 백엔드에만 국한되지 않고 모든 백엔드에서 관찰될 수 있었기 때문입니다.

따라서 대기 이벤트와 프로세스 ID만으로는 오버플로우를 일으킨 백엔드를 식별할 수 없었습니다. 해당 대기 이벤트가 오버플로우를 발생시킨 하나의 백엔드뿐 아니라 그 영향을 받는 모든 백엔드에서 나타날 수 있기 때문입니다.


4. 서브트랜잭션 오버플로우 모니터링

서브트랜잭션 오버플로우를 생성하는 쿼리를 식별하기 위해 고객에게 각 백엔드의 서브트랜잭션 수와 오버플로우 상태를 정기적으로 모니터링할 수 있는 커스텀 확장을 제공했습니다.

이후 이 작업은 PostgreSQL 오픈 소스 코드에 커밋되었습니다. 이를 통해 서브트랜잭션 수와 오버플로우 상태를 모니터링할 수 있는 새로운 뷰인 pg_stat_get_backend_subxact()가 제공되었습니다.

커스텀 확장의 도움으로 사용자는 서브트랜잭션 오버플로우를 발생시키는 애플리케이션 로직을 찾을 수 있었습니다. 애플리케이션 설계를 바탕으로 서브트랜잭션 수를 줄이려 했지만, 기본 비즈니스 로직을 유지하면서 이를 적용할 방법은 없었습니다.


5. 고객 환경을 위한 핫픽스 제공

문제가 기업 전체에 미치는 광범위한 영향을 고려할 때, 원활한 운영을 보장할 임시 해결책이 필요했습니다. 서브트랜잭션 캐시 오버플로우를 해결하기 위해 세션당 서브트랜잭션 캐시 한도를 64에서 256으로 높이는 핫픽스 패치를 배포했습니다. 이 수치는 애플리케이션에서 서브트랜잭션을 최대한 사용한 경우를 바탕으로 정했습니다.

이 조정은 각 스냅샷의 메모리 사용량을 늘리고 일부 성능 저하를 일으킬 수 있었습니다. 하지만 서브트랜잭션 캐시 오버플로우로 애플리케이션이 차단되는 것을 방지하는 임시 조치로 작용했습니다. 이 핫픽스는 최종 해결책이 아니라 비즈니스 연속성을 유지하기 위한 실용적인 단계였습니다.

이를 통해 고객은 다음 Postgres 릴리스까지 기다리지 않고 버그 수정 사항을 적용할 수 있었습니다. 또한 수정 사항을 고객 전용 릴리스에서 유지했기 때문에 다른 고객은 이 상수 변경이 애플리케이션에 미칠 수 있는 부정적인 영향을 걱정할 필요가 없었습니다.


6. PostgreSQL SLRU의 근본적인 문제 해결

고객 문제를 해결한 후에는 Postgres SLRU에서 오랫동안 해결되지 않았던 성능 문제를 개선하는 작업을 시작했습니다. 이 문제는 수년간 여러 블로그에서 논의되었으며[4], 여러 차례 해결이 시도되었지만 당시까지 성공하지 못했습니다.

저자는 pgbench 워크로드로 문제를 로컬에서 재현하고 더 자세히 분석했습니다. 또한 여러 회의에서 이 문제를 논의했습니다[2].

이러한 논의를 바탕으로 과거 해결책의 장점과 한계를 분석하고, 기존 아이디어에 새로운 접근법을 더해 문제를 해결할 방법을 설계했습니다. 이 솔루션은 회의에서도 발표되었습니다[3].

작업 과정에서는 PostgreSQL 커미터인 Robert Haas와 Alvaro Herrera로부터 지속적인 지원을 받았습니다.

솔루션 게시와 PostgreSQL 커밋 과정

솔루션을 구현하고 고객 환경에서 다양한 성능 테스트와 검증을 진행한 후, 해당 솔루션을 PostgreSQL 오픈 소스 커뮤니티에 게시했습니다[5].

커뮤니티 검토 과정에서 많은 설계 및 코드 변경이 이루어졌고, 최종적으로 Alvaro Herrera가 솔루션을 PostgreSQL 오픈 소스에 커밋했습니다. 문제와 구현한 해결책을 자세히 설명하는 블로그도 작성되었습니다. 이 해결책은 Postgres 17에 포함될 예정이라고 발표되었습니다[6].

수정 후 PostgreSQL 성능 분석

수정되지 않은 버전과 수정된 버전의 성능 지표를 비교했습니다. 클라이언트 수가 많아지면 기본 코드의 성능이 현저히 저하된 반면, 패치가 적용된 버전은 훨씬 나은 성능을 보였습니다. 테스트 결과, 수정된 버전은 수정되지 않은 버전보다 약 2.5~3.0배 빠르게 실행되었습니다.

테스트 머신

  • Intel 128 코어 머신, 512 GB RAM, 8 CPU

테스트 조건

  • 다양한 클라이언트 수(1~128)로 pgbench 테스트 실행
  • 서브트랜잭션 캐시 오버플로우를 병렬로 생성
    • 트랜잭션 내에서 70개의 세이브포인트 생성
    • 1초 대기 후 커밋
    • 테스트 실행 중 이 과정 반복
  • 장기 실행 트랜잭션 실행
    • 트랜잭션 ID만 부여
    • 10초 대기 후 커밋
    • 테스트 실행 중 이 과정 반복

테스트 결과

클라이언트 30명부터 성능 저하가 두드러졌지만, 해결책을 구현한 후에는 클라이언트 70명까지 성능이 선형적으로 확장되었습니다.

PostgreSQL SLRU 수정 전후 클라이언트 수별 성능 비교 그래프


결론: 고객 문제에서 PostgreSQL 커밋으로

버그는 혼란을 일으키지만 개선과 혁신, 고객 만족을 이끄는 촉매제가 되기도 합니다. 투명성, 협업 및 문제 해결 문화를 바탕으로 대응하면 더욱 견고하고 신뢰할 수 있는 소프트웨어 솔루션으로 발전시킬 수 있습니다.

이 사례는 오픈 소스 소프트웨어에서 오랫동안 해결되지 않았던 문제가 고객에게 영향을 미치면서 본격적으로 분석된 과정입니다. 다양한 포럼에서 문제를 제기해 관심을 높이고, 최종적으로 PostgreSQL 커뮤니티와 협력해 해결책을 오픈 소스 코드에 반영했습니다.


PostgreSQL 서브트랜잭션 FAQ

PostgreSQL에서 SubtransSLRU와 SubtransBuffer 대기 이벤트는 왜 발생하나요?

두 대기 이벤트는 일반적으로 pg_subtrans SLRU 서브시스템에 과도한 부하가 걸릴 때 발생합니다. 서브트랜잭션 캐시가 오버플로우하면 여러 백엔드가 SLRU 캐시 접근을 두고 경쟁하고, 장기 실행 트랜잭션은 디스크 페이지 로드와 I/O를 증가시킬 수 있습니다.

PostgreSQL 서브트랜잭션 캐시는 언제 오버플로우하나요?

이 사례에서 PostgreSQL은 최상위 트랜잭션당 64개의 서브트랜잭션을 캐시했습니다. 하나의 트랜잭션이 64개를 초과하는 서브트랜잭션을 생성하면 캐시가 오버플로우 상태가 됩니다.

서브트랜잭션 오버플로우를 일으킨 백엔드를 어떻게 확인했나요?

고객 환경에는 백엔드별 서브트랜잭션 수와 오버플로우 상태를 정기적으로 모니터링하는 커스텀 확장이 제공되었습니다. 이후 관련 작업은 PostgreSQL 오픈 소스 코드에 커밋되어 pg_stat_get_backend_subxact() 뷰를 제공했습니다.

고객 환경에는 어떤 임시 해결책이 적용되었나요?

세션당 서브트랜잭션 캐시 한도를 64에서 256으로 높이는 고객 전용 핫픽스 패치가 배포되었습니다. 메모리 사용량 증가와 일부 성능 저하 가능성이 있었지만, 비즈니스 연속성을 유지하기 위한 임시 조치였습니다.

PostgreSQL SLRU 수정 후 성능 테스트 결과는 어땠나요?

본문의 테스트 환경에서 수정된 버전은 수정되지 않은 버전보다 약 2.5~3.0배 빠르게 실행되었습니다. 기본 코드는 클라이언트 30명부터 성능 저하가 두드러졌지만, 해결책 적용 후에는 클라이언트 70명까지 선형적으로 확장되었습니다.


참고 자료

  1. PostgreSQL 커밋 메시지
  2. PostgreSQL 서브트랜잭션 관련 회의 영상
  3. PostgreSQL SLRU 솔루션 발표 영상
  4. PostgreSQL Subtransactions Considered Harmful
  5. PostgreSQL 오픈 소스 커뮤니티 제안
  6. Postgres 17 Configurable SLRU Cache

원문: The Life of a Bug: From Customer Escalation to PostgreSQL Commit

EDB 영업 기술 문의: 02-501-5113

이메일: salesinquiry@enterprisedb.com

EDB 홈페이지에서 문의하기

Share this