← 모든 글

Postgres extension 을 도입할 때 우리가 검토하는 5가지

PostgreSQL extension은 도입 비용이 없어 보이지만, 결제·정산·자동화를 직접 운영하는 현장에서는 호환성·백업 무결성·쿼리 플래너·대안 비용까지 다섯 가지를 체계적으로 검토해야 후회가 없다.

우리가 Extension을 신중하게 보는 이유 — 결제·정산 현장의 맥락

결제·정산 시스템은 데이터베이스에 무겁게 의존한다. 트랜잭션 상태 추적, 파트너사별 정산 배치, 이중 지불 감지, 감사 로그까지 — HEDVION에서 PostgreSQL은 단순한 저장소가 아니라 비즈니스 로직의 절반이 살아있는 공간이다. 그렇기 때문에 "편의를 위한 extension 하나"가 나중에 얼마나 비싼 운영 비용으로 돌아오는지를 몸으로 배웠다.

처음 겪은 일은 pg_trgm을 이용한 거래처 검색 기능이었다. 도입 당시에는 문자열 유사도 검색을 순식간에 해결해 주는 마법처럼 보였다. 그런데 3개월 뒤 Postgres 마이너 버전 업그레이드 과정에서 pg_trgm이 등록한 GIN 인덱스가 기존 정산 집계 쿼리의 실행 계획을 바꿨고, 특정 파트너사 정산 배치가 평소보다 4배 느리게 돌았다. 배치가 SLA를 넘기기 시작한 뒤에야 원인을 찾았다. 그때부터 우리는 다섯 가지를 체계적으로 검토하기 시작했다.

체크 1: 관리형 DB 환경에서 실제로 설치되는가

PostgreSQL extension 생태계는 공식 저장소에만 300개가 넘는다. 그러나 AWS RDS, Aurora, Supabase 같은 관리형 서비스를 쓰는 팀에게는 이 목록이 절반 이하로 줄어든다. RDS는 "trusted extensions" 리스트를 별도로 관리하며, 이 목록 밖의 extension은 superuser 권한이 있어도 CREATE EXTENSION이 실패한다. 2025년 기준 RDS가 지원하는 extension은 약 85개로, PostGIS나 pg_stat_statements 같은 주류 extension은 포함되지만 TimescaleDB나 Citus처럼 아키텍처를 바꾸는 extension은 지원하지 않는다.

우리가 실제로 겪은 케이스가 있다. 자동화 배치 스케줄러에서 시계열 집계를 빠르게 하려고 TimescaleDB를 검토했다. 로컬에서 CREATE EXTENSION timescaledb가 정상 동작하는 것을 확인하고 개발 기간을 3주 투자했는데, 스테이징 환경(RDS)에서 설치 자체가 불가능했다. 결국 Postgres의 date_trunc + 파티셔닝으로 같은 결과를 내는 방식으로 재설계했다. 3주가 날아갔다. 지금은 새 extension을 검토할 때 가장 먼저 SHOW rds.extensions(혹은 Supabase 대시보드의 Extensions 탭)에서 지원 여부부터 확인한다. 이 한 줄이 수 주의 낭비를 막아준다.

체크 2: 다음 Postgres 메이저 버전에서도 살아남는가

PostgreSQL은 매년 10월 메이저 버전을 릴리스하고, 5년 지원 사이클 이후 EOL을 선언한다. 결제 시스템을 운영하는 팀에게 DB 버전 업그레이드는 "언젠가 해야 할 일"이 아니라 보안 패치와 직결된 강제 이벤트다. Postgres 11은 2023년 11월, 12는 2024년 11월에 EOL이 됐다. 해당 버전에만 의존하는 extension을 쓰고 있다면, 업그레이드 당일 그 extension이 서비스 블로커가 된다.

우리 팀이 검토하는 기준은 세 가지다. 첫째, GitHub 저장소에서 최근 6개월 내 커밋이 있는가. 둘째, Postgres 최신 2개 메이저 버전(예: 16, 17)에 대한 CI 테스트가 돌고 있는가. 셋째, 메인테이너가 1인이 아닌가 — 개인 프로젝트는 메인테이너가 이직하거나 관심을 잃는 순간 사실상 고아가 된다. pg_cron은 이 세 기준을 모두 통과했고, 우리가 정산 배치 자동화에 적극적으로 쓰고 있다. 반면 어떤 통계 함수 extension은 마지막 커밋이 2022년이고 CI에서 Postgres 15조차 테스트되지 않아 후보에서 제외했다. 이 판단 기준을 적용하면 "매력적이지만 위험한" extension을 비교적 빠르게 걸러낼 수 있다.

체크 3: pg_dump·복원 파이프라인이 깨지지 않는가

결제 데이터는 법적으로 일정 기간 보존해야 하는 경우가 많다(국내 전자금융거래법 기준 최소 5년). 이 말은 백업·복원 파이프라인이 단순한 DevOps 편의 기능이 아니라 규정 준수의 일부라는 뜻이다. pg_dump는 extension 데이터를 덤프할 수 있지만, 복원 시 해당 extension의 바이너리가 대상 서버에 없으면 pg_restore가 실패한다. C로 작성된 extension일수록 이 문제가 더 심각하다.

우리가 사용하는 검증 절차는 단순하지만 효과적이다. 도입 후보 extension을 로컬에 설치하고 테스트 데이터를 넣은 뒤, pg_dump -Fc로 덤프하고 extension이 없는 별도의 빈 컨테이너에서 pg_restore를 실행한다. 이 과정이 에러 없이 끝나야 다음 체크로 넘어간다. 한 번은 PostGIS 기반의 좌표 저장 기능을 검토하면서 이 테스트를 돌렸는데, extension 없는 환경에서 ERROR: could not open extension control file이 발생했다. 실제 재해 복구 상황이었다면 복원 불가 상태가 됐을 것이다. 이 체크 덕분에 도입 전에 발견해, 복원 절차에 extension 선행 설치 스텝을 명시적으로 추가하게 됐다.

체크 4: 쿼리 플래너를 건드리는가 — 숨어있는 성능 회귀

일부 extension은 PostgreSQL의 플래너 훅(planner hook)이나 커스텀 스캔 노드(custom scan node)를 등록한다. 이 경우 extension 설치 이전에 잘 동작하던 쿼리가 설치 이후 다른 실행 계획을 선택할 수 있다. 특히 정산 집계처럼 대용량 데이터를 스캔하는 쿼리는 실행 계획 한 줄 차이가 쿼리 시간을 수십 배 바꾸기도 한다.

우리는 새 extension을 설치하기 전에 핵심 쿼리 10~15개의 EXPLAIN (ANALYZE, BUFFERS) 결과를 파일로 저장한다. 설치 후 같은 쿼리를 다시 돌려서 Seq Scan ↔ Index Scan 전환, cost 추정치 변화, 실제 실행 시간 변화를 비교한다. 앞서 언급한 pg_trgm 사례가 이 절차를 만든 직접적인 계기다. 그때 설치 전후 비교를 했더라면, GIN 인덱스 생성이 특정 집계 쿼리의 플래너 판단을 바꾸는 것을 미리 잡을 수 있었다. 지금은 이 비교를 스테이징 배포 체크리스트에 명시적으로 넣어두고, PR 리뷰 때 EXPLAIN 스크린샷을 첨부하게 한다.

체크 5: Extension이 정말 최선인가 — 대안 비용과의 트레이드오프

이 질문이 가장 단순하지만 가장 자주 건너뛰인다. Extension은 "이미 있는 기능"을 가져다 쓰는 것처럼 느껴지기 때문에 비용이 없어 보인다. 그러나 extension 하나를 추가할 때마다 운영 지식(설정 파라미터, 모니터링 지표, 업그레이드 절차)이 쌓인다. DB를 주로 다루는 사람이 1~2명인 작은 팀에서는 이 숨은 지식 부채가 생각보다 빨리 부담이 된다.

우리 팀이 쓰는 판단 기준은 "이 기능을 application 레이어에서 구현하면 얼마나 걸리는가"와 "extension을 운영하는 비용(업그레이드, 모니터링, 문서화)을 연간으로 환산하면 얼마인가"를 비교하는 것이다. 거래 데이터에서 패턴 기반 이상 감지를 구현할 때, DB 레벨 extension 대신 Python 배치 스크립트를 선택한 적이 있다. Extension 방식은 초기 개발 2일이 절약됐지만, Postgres 버전별 호환성 관리와 배포 파이프라인 수정 비용을 감안하면 1년 기준으로 application 처리 쪽이 더 저렴하다는 결론이었다. Extension 수를 줄이는 것 자체가 운영 단순화이고, 작은 팀에게 단순함은 곧 실행 속도다.

내일 당장 쓸 수 있는 실행 체크리스트

다섯 가지 체크를 현장에서 바로 적용할 수 있는 절차로 정리하면 다음과 같다.

도입 전 (제안 단계)

  • SHOW rds.extensions 또는 관리형 서비스의 지원 extension 목록 확인 → 없으면 대안 즉시 검토, 개발 시작 전에 결정
  • GitHub 저장소에서 최근 6개월 내 커밋 여부, Postgres 최신 2버전 CI 배지 포함 여부, 메인테이너 수 확인
  • "application 레이어에서 구현하면 얼마나 걸리는가"를 반드시 estimating해서 제안서에 병기

도입 중 (스테이징 검증 단계)

  • 핵심 쿼리 10~15개의 EXPLAIN (ANALYZE, BUFFERS) 결과를 파일로 저장 → extension 설치 후 재비교, PR에 스크린샷 첨부
  • Extension 없는 빈 컨테이너에서 pg_dump -Fcpg_restore 전 과정 실행, 에러 유무 확인 후 복원 RunBook 업데이트

도입 후 (운영 단계)

  • pg_available_extension_versions를 분기별로 확인해 업데이트 가능 버전 추적
  • Postgres 메이저 업그레이드 계획 수립 시, 사용 중인 extension별 호환 버전 테이블을 별도 문서로 유지하고 업그레이드 M-3개월 시점에 선제 검토

Extension 하나가 팀의 배포 용기(deployment courage)를 얼마나 갉아먹을 수 있는지는 직접 겪어봐야 안다. 위 체크리스트는 그 경험을 미리 대신해 주는 방어선이다. 처음 한 번 꼼꼼히 적용하면, 이후 도입 판단은 훨씬 빨라지고 "나중에 후회"하는 케이스는 확실히 줄어든다.

* 위 링크는 인프런 affiliate 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

📚 추천 강의
한 입 크기로 잘라먹는 바이브코딩 (with Claude Code)
Claude Code로 바이브코딩, 개발자라면 꼭 들어야 할 필수 강의
강의 보러가기 →

* 위 추천 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.