이 문서에서는 언어, 풀링 모드, 단일 또는 다중 테넌트 모델, 순수 풀링 이상의 기능 등 세 가지 풀러의 아키텍처를 비교합니다. Tembo와 PkgPulse는 이 세 가지 도구의 수치 비교를 발표했지만 측정 결과를 직접 재현하지는 않았습니다. 벤치마크 방법론에 자세히 설명된 벤치마크에 대한 우리의 편집 입장은 우리가 직접 확인하지 않은 수치를 절대 다시 게시하지 않는다는 것입니다. 대신 여기에서 찾을 수 있는 내용은 각 도구의 실제 아키텍처, Aurabase가 실제로 Postgres 트래픽을 라우팅하는 방법, 소스 코드에서 섹션별로 검증된 내용입니다.
- PgBouncer(C)는 가장 입증된 풀러로 남아 있으며 Kubernetes와 가장 잘 통합됩니다. CloudNativePG는
Pooler리소스를 위해 PgBouncer에 직접 의존합니다. - Supavisor(Elixir, Supabase 프로젝트)는 데이터베이스당 하나의 풀러가 아닌 동일한 서비스에서 수천 개의 데이터베이스를 제공하는 다른 문제를 목표로 합니다.
- PgCat(Rust)은 애플리케이션 샤딩, 복제본 간의 로드 밸런싱, 원시 풀링에 대한 자동 장애 조치를 추가합니다.
- Aurabase 저장소는 두 가지 수준, 즉 공유 플릿을 위한 공유 배포와 전용 테넌트별로 CloudNativePG에서 관리하는
Pooler리소스에서 사용되는 PgBouncer를 보여줍니다. 둘 다 트랜잭션 모드에서 작동합니다. - PostgREST 및
aura-db관리 풀은 풀러를 통하지 않고 자발적으로 Postgres에 직접 연결되어 있습니다. 트랜잭션 풀링은 스키마 재로드 및 세션 잠금을 중단합니다.
세 명의 풀러, 세 가지 철학
PgBouncer는 다중 테넌트 규모의 Supavisor 풀을 최소화하고 PgCat은 원시 풀링에 네트워크 기능을 추가합니다. 세 가지 중 어느 것도 다른 두 가지를 직접 대체하지는 않지만 종종 같은 페이지에서 용어를 비교합니다.
| 언어 | C | 엘릭서(빔) | 녹 |
|---|---|---|---|
| 풀링 모드 | 세션, 트랜잭션, 명세서 | 세션, 트랜잭션 | 세션, 트랜잭션, 명세서 |
| 테넌시 모델 | 단일 테넌트로 설계된 인스턴스당 하나의 대상 클러스터 | 네이티브 멀티 테넌트: 많은 데이터베이스를 위한 서비스 | 파티션 키를 기준으로 샤딩하는 대상 클러스터 |
| 풀링을 넘어 | 추가 기능 없음, 의도적으로 최소화 | 관리 HTTP API, 동적 테넌트 등록 | 복제본 간 샤딩, 로드 밸런싱 및 장애 조치 |
| 기본 Kubernetes 통합 | 예: CloudNativePG 리소스 풀러 | 현재까지 기본적으로 문서화되지 않았습니다. | 현재까지 기본적으로 문서화되지 않았습니다. |
| 원산지 | Postgres 풀링의 역사적 표준 | 자체 멀티 테넌트 클라우드를 위해 Supabase에서 구축 | Instacart에서 탄생하여 현재 PostgresML에서 관리하고 있습니다. |
열(순서): PgBouncer, Supavisor, PgCat. 각 프로젝트의 공식 제출에 따른 아키텍처 특성은 배포 중인 버전에서 확인되며, 이 시점에서 생태계는 빠르게 발전합니다.
역사적인 표준, 가볍고 Kubernetes에 통합됨
PgBouncer는 추가 기능 없이 Postgres 연결 풀링이라는 한 가지 작업만 수행합니다. 이렇게 고의적으로 좁은 범위는 프로덕션 환경에서 대부분의 Postgres 스택의 기본 빌딩 블록으로 채택되는 수명과 채택을 크게 설명합니다.
Three pooling modes are available. Session mode opens one server connection per client connection, the most permissive. Transaction mode reuses a server connection between several clients, released at each end of a transaction. Statement mode goes even further, and is rarely used in production. It is the transaction mode that brings the real pooling gain, but it imposes strict rules. Any session state (SETvariables, advisory locks, LISTEN/NOTIFY) does not survive beyond a transaction. We detail these rules and their pitfalls in our dedicated article on the transaction pooling mode of PgBouncer.
역사적으로 단일 프로세스인 PgBouncer 인스턴스는 기본적으로 단일 CPU 코어를 사용합니다. 동일한 포트 뒤에서( SO_REUSEPORT를 통해) 여러 인스턴스를 실행하는 것은 초기 설계 기능이 아니라 프로젝트의 최신 발전입니다. 인증 측면에서 PgBouncer는 역할의 비밀번호를 동적으로 확인하기 위해 각 연결에서 실행되는 SQL 함수인 구성 가능한 auth_query를 지원합니다. 이 메커니즘은 각 사용자를 미리 나열하는 정적 파일에 의존하지 않습니다. Aurabase가 프로젝트별 역할에 사용하는 것이 바로 이 메커니즘입니다(섹션 05).
PgBouncer는 CloudNativePG가 Pooler리소스 뒤에 기본적으로 배포하는 풀러입니다. CloudNativePG 운영자가 관리하는 Postgres 클러스터에서 관리형 풀러를 활성화하는 것은 실제로 직접 구성하지 않고도 PgBouncer를 활성화하는 것과 같습니다.
Supabase의 클라우드 기반 다중 테넌트 풀러
Supavisor는 PgBouncer가 이 규모로 해결하도록 설계되지 않은 문제를 해결합니다. 여기에는 데이터베이스당 하나의 풀러 인스턴스가 아닌 단일 서비스에서 매우 많은 수의 개별 테넌트 데이터베이스를 제공하는 것이 포함됩니다. Elixir로 작성되고 Erlang 가상 머신(BEAM)에서 실행되는 이 프로젝트는 Supabase의 자체 GitHub 저장소에서 오픈 소스로 개발 및 유지 관리됩니다.
기본 다중 테넌트 모델은 실제 구조적 차이입니다. 기존 PgBouncer 집합에 대상 기반당 하나의 프로세스(또는 전용 연결 집합)가 필요한 경우 Supavisor는 다르게 작동합니다. HTTP 관리 인터페이스를 통해 테넌트를 동적으로 등록하고 서비스를 다시 시작하지 않고도 들어오는 각 연결을 올바른 데이터베이스로 라우팅합니다. Supabase는 바로 이러한 이유로 자체 클라우드 프로젝트를 PgBouncer에서 Supavisor로 마이그레이션했습니다. 데이터베이스당 하나의 클래식 풀링 클러스터는 수십만 개의 프로젝트를 호스팅하는 다중 테넌트 클라우드로 확장되지 않습니다.
이 아키텍처 선택에는 문서화된 단점이 있습니다. 고급 사례에 대한 PgBouncer와의 기능 패리티는 프로젝트 출시 후 안정화되는 데 시간이 걸렸습니다. 두 가지 예: LISTEN/NOTIFY의 특정 동작 및 트랜잭션 모드에서 준비된 문의 정밀한 관리. 애플리케이션이 이러한 특정 동작에 의존하는 경우 마이그레이션하기 전에 버전을 확인하세요.
Rust 외부인: 기본 샤딩 및 로드 밸런싱
PgCat은 Rust로 작성된 PgBouncer의 대안으로 명시적으로 배치되었습니다. PgBouncer나 Supavisor가 기본적으로 포함하지 않는 클래식 풀링에 네트워크 기능을 추가합니다. 특히 세 가지: 파티션 키에 의한 애플리케이션 샤딩, 읽기 전용 복제본 간의 로드 밸런싱, 실패한 복제본으로부터의 자동 장애 조치입니다. 이 프로젝트는 Instacart에서 탄생한 후 현재 PostgresML에 의해 인수 및 유지 관리되고 있습니다.
구체적으로 PgCat은 일반적으로 두 개의 서로 다른 계층(연결 풀러 및 여러 Postgres 인스턴스 간 라우팅을 위한 애플리케이션 프록시)을 차지하는 역할을 수행할 수 있습니다. 이미 데이터를 직접 분할하고 있던 팀은 PgCat을 사용하여 코드를 단순화할 수 있습니다. 내부적으로 개발된 복제본 간에 읽기를 배포하는 논리도 마찬가지입니다. 전용 네트워크 계층이 이를 직접 대체합니다.
반대의 타협도 존재합니다. PgCat은 PgBouncer보다 문서 및 생산 피드백 생태계가 훨씬 작은 젊은 프로젝트입니다. 샤딩 및 장애 조치 기능을 채택한다는 것은 풀링 용량뿐만 아니라 이 특정 구성 요소의 성숙도에 의존하는 데 동의한다는 의미이기도 합니다.
Aurabase 코드가 보여주는 것: 트랜잭션 풀링이 모든 것을 망가뜨리는 곳을 제외한 모든 곳의 PgBouncer
Aurabase 저장소는 트랜잭션 모드에서 두 개의 개별 계층에 PgBouncer를 배포합니다. 공유 플릿의 경우 Helm 차트는 공유 데이터 플레인(deploy/helm/aurabase/templates/infra/pgbouncer.yaml, 이미지 edoburu/pgbouncer) 앞에 전용 PgBouncer 배포를 정의합니다. 전용 인스턴스의 테넌트의 경우 프로비저닝 프로그램은 CloudNativePG에서 기본적으로 관리하는 Pooler 리소스(deploy/cnpg/tenant-pooler.yaml, k8s_tenant.rs에서 렌더링)를 생성합니다. Supavisor나 PgCat도 사용하지 않습니다. 코드는 이 선택 이전의 명시적인 비교를 문서화하지 않습니다. 반면에 PgBouncer가 기본 풀링 브릭이라는 사실과 일치하여 CloudNativePG 생태계와의 심층적이고 이미 운영 가능한 통합을 보여줍니다.
그러나 모든 것이 풀러를 통과하는 것은 아니며 이는 코드 자체에 문서화된 의도적인 선택입니다. PostgREST는 PgBouncer를 통하지 않고 Postgres에 실시간으로 연결되어 있습니다. Helm 차트 주석은 이유에 대해 명시적으로 설명합니다. 트랜잭션 풀링은 pgrst채널의 LISTEN에 따라 스키마 재로드를 중단합니다. 이 메커니즘은 클라이언트 간의 재활용 서버 연결과 호환되지 않습니다.aura-db 관리 풀(스키마, DDL, 세션 권고 잠금)도 동일한 기본 이유로 직접 연결 상태로 유지됩니다. 트랜잭션 범위가 아닌 SET search_path 및 세션 잠금은 트랜잭션 모드 풀러에서 유지되지 않습니다.
인증은 정적 userlist.txt 파일 없이 섹션 02: AUTH_QUERY: SELECT * FROM pgbouncer.user_lookup($1)에 설명된 auth_query 패턴을 따릅니다. 이를 통해 프로젝트별로 동적으로 생성된 역할(project_<uuid>_authenticator)이 새 프로젝트마다 풀러를 다시 배포하지 않고도 PgBouncer를 통해 인증할 수 있습니다.
로컬 Kubernetes 매니페스트의 PgBouncer 상태 확인 주석은 이미 수정된 실제 버그를 문서화합니다. PgBouncer에 대해 실행되는 pg_isready는 프록시 핸드셰이크만 검증하며, 릴레이하는 Postgres 백엔드에 대한 실제 연결은 검증하지 않습니다. PgBouncer는 백엔드가 중지된 경우에도 "연결 수락"에 응답하여 요청을 대기열에 넣습니다. 파괴적인 테스트 중에 관찰된 결과: Postgres에 연결할 수 없는 동안 서비스는 연속 5주기 동안 healthy 상태로 유지되었습니다. 수정 사항은 검사를 풀러를 통해 백엔드까지 진정한 엔드 투 엔드 psql 요청으로 대체합니다. 동일한 테스트에서 수정 후 재생된 결과: unhealthy가 7주기, 약 35초 동안 감지되었습니다.
사소하지만 드러나는 마지막 세부 사항: Helm 차트는 기본적으로 edoburu/pgbouncer:v1.24.1-p1를 고정하는 반면 로컬 k3d 벤치는 v1.25.2-p0을 사용합니다. 이는 아키텍처 선택이 아니며 두 환경 간의 버전 동기화가 약간 부족할 뿐이며, 코드 검토가 블로그 게시물보다 더 빨리 파악하는 세부 사항입니다. 우리는 그것을 꾸미기보다는 있는 그대로 기록합니다. 이 풀러가 제공하는 스키마 분할에 대한 자세한 내용은다중 테넌트 RLS 격리에 대한 문서를 참조하세요.
세 가지 중에서 선택하는 방법
다음과 같은 경우 PgBouncer를 선택하세요.
- 일반적으로 CloudNativePG 또는 Kubernetes에서 관리하는 Postgres 클러스터
- 가장 입증되고 잘 문서화된 풀러를 원합니다.
- 풀러 인스턴스당 대상 기반이 귀하에게 적합합니다.
다음과 같은 경우 Supavisor를 선택하세요.
- 동일한 서비스 뒤에 있는 수백 또는 수천 개의 기지
- 재배포 없이 API를 통해 동적으로 테넌트를 등록해야 함
- 이미 Supabase 생태계에 있거나 이에 의존할 의향이 있음
다음과 같은 경우 PgCat을 선택하세요.
- 풀러 수준에서 애플리케이션 공유가 이미 실행 중이거나 계획되어 있습니다.
- 별도의 애플리케이션 계층이 없는 로드 밸런싱 및 장애 조치 복제본
- PgBouncer보다 문서화가 적고 더 젊은 프로젝트에 익숙함
어떤 풀러를 선택하더라도 Postgres 자체의 크기를 대체하지는 않습니다. 풀 크기와 서버 max_connections은 차례로 생각하는 것이 아니라 함께 생각해야 합니다. 너무 낮은 max_connections 앞에 있는 넉넉한 풀은 단순히 채도를 한 수준에서 다른 수준으로 이동시킵니다. max_connections 조정 가이드에서는 풀 크기를 설정하기 전에 적용할 크기 조정 공식을 자세히 설명합니다.
우리가 가장 자주 묻는 질문
범용 풀러는 없으며 임대차에 딱 맞는 풀러만 있습니다.
PgBouncer, Supavisor 및 PgCat은 동일한 도구의 세 가지 버전이 아니라 동일한 문제의 세 가지 변형을 해결합니다. PgBouncer는 플랫폼이 이미 Kubernetes 및 CloudNativePG를 사용하고 있거나 단순히 가장 문서화된 풀러를 원하는 경우 가장 안전한 선택입니다. Supavisor는 동일한 서비스에서 제공되는 특정 수의 기지를 넘어서 관련성이 높아집니다. 더 젊은 프로젝트의 성숙도를 수용한다면 네트워크 수준에서 샤딩 및 복제본 장애 조치를 놓친 경우 PgCat을 우회할 가치가 있습니다.
Aurabase 코드는 중립적이지 않은 일관적인 선택을 보여줍니다. 트랜잭션 모드의 PgBouncer는 두 가지 수준, 전용 테넌트당 공유 플릿 및 CNPG 풀러입니다. PostgREST와 스키마 관리에 대해 문서화된 두 가지 예외가 남아 있습니다. 종이가 아닌 실제 프로젝트 사일로를 보려면 성능 페이지에 관련 측정 방법이 문서화되어 있습니다.