PROD주권 유럽 BaaS 플랫폼대시보드 열기 →

성능 · 9분 읽음

풀러가 없는 Postgres max_connections

Affane Daylami · Fondateur · 2026년 6월 6일

블로그로 돌아가기

서버 앞에서 풀링하지 않으면 max_connections는 Postgres가 병렬로 효율적으로 처리할 수 있는 요청 수가 아니라 열려 있는 모든 클라이언트 연결을 동시에 처리해야 합니다. 이 두 숫자를 혼동하는 것은 max_connections를 잘못 설정하는 가장 일반적인 원인입니다. 로드를 흡수하기에는 너무 낮거나 실제로 사용 가능한 메모리에 비해 너무 높습니다.

이 영어 텍스트는 프랑스어 원본에서 자동으로 생성되었으며 아직 검토되지 않았습니다.
이 페이지는 자동으로 번역되었습니다. 영어 버전은 권위가 있습니다.

이 기사에서는 하드웨어의 이상적인 동시성을 계산하기 위해 PostgreSQL 위키에서 게시한 공식(생태계에서 가장 많이 인용되는 연결 풀 크기 조정 공식)을 제공하고 각 연결 비용이 애플리케이션 스레드보다 더 비싼 이유를 설명한 다음 추측하지 않고 max_connections를 설정하는 절차를 자세히 설명합니다. 우리의 벤치마크 방법론은 이 블로그의 모든 성능 주장에 사용되는 측정 프로토콜을 문서화합니다.

필수사항

  • 풀링이 없으면 max_connections는 Postgres가 병렬로 효율적으로 처리할 수 있는 연결뿐만 아니라 모든 동시 클라이언트 연결을 포괄해야 합니다.
  • PostgreSQL 위키 참조 공식: 이상적인 활성 동시성 = (물리적 코어 × 2) + 효율적인 디스크. 엄격한 한계가 아닌 측정을 통해 검증할 시작점입니다.
  • max_connections는 postmaster 컨텍스트 매개변수입니다. 이를 변경하려면 간단한 다시 로드가 아니라 서버를 완전히 다시 시작해야 합니다.
  • 각 Postgres 연결은 경량 스레드가 아닌 별도의 시스템 프로세스입니다. 이로 인해 연결 수가 증가하자마자 오버헤드가 발생하게 됩니다.
  • 코드에서 확인됨: 전용 Postgres 클러스터에서 Aurabase는 클러스터 크기에 따라 max_connections를 50(무료 계층)에서 400(엔터프라이즈 계층)까지 다양하게 변경합니다.
#
진단

Postgres 연결이 애플리케이션 스레드보다 비용이 더 많이 드는 이유

Postgres는 연결에 경량 스레드 풀을 사용하지 않습니다. 각 클라이언트 연결은 완전한 시스템 프로세스를 트리거합니다.

postmaster 프로세스는 각 연결 시도에 대해 이 단일 세션이 닫힐 때까지 전용으로 새로운 세션("포크")을 생성합니다. 공식 프로젝트 문서는 아키텍처 기본 사항에 대한 장(postgresql.org/docs/current/connect-estab.html, "Connection Semantics" 섹션, 2026년 8월 24일 액세스)에서 이 메커니즘을 정확하게 설명합니다.

이 선택에는 실질적인 이점이 있습니다. 한 연결의 충돌이 다른 연결에 영향을 주지 않으며 각 프로세스가 서버의 나머지 부분과 격리됩니다. 또한 직접적인 비용도 발생합니다. 각각의 추가 연결은 자체 메모리 공간과 커널에 대한 자체 컨텍스트 전환 오버헤드를 포함하여 예약할 전체 OS 프로세스를 추가합니다.

실제로 변경되는 사항

풀링 없이 Postgres에 500개의 직접 연결을 여는 애플리케이션은 서버가 500개의 동시 시스템 프로세스를 관리하도록 강제합니다. 이는 대다수가 두 요청 사이에 유휴 상태로 남아 있더라도 마찬가지입니다.

#
메모리 비용

연결이 실제로 소비하는 것: 공유 메모리와 work_mem

두 가지 서로 다른 메커니즘이 기억에 영향을 미치며, 이를 혼동하면 거의 항상 오진이 발생합니다.

첫 번째는 고정되어 있습니다. 시작 시 Postgres는 이러한 연결이 이후에 열리는지 여부에 관계없이 max_connections 값에 따라 크기가 지정된 공유 메모리 구조(잠금, 프로세스 테이블)를 예약합니다. 설정에 대한 공식 문서에서는 이 설정을 늘리면 OS의 기본 구성에서 허용하는 것보다 더 많은 시스템 공유 메모리가 필요할 수 있다고 명시합니다(postgresql.org/docs/current/runtime-config-connection.html, 2026년 8월 24일 액세스).

두 번째는 가변적이며 규모면에서 훨씬 더 위험합니다. work_mem는 연결당 한 번 할당되지 않고 쿼리 계획의 정렬 또는 해싱 작업당 한 번 할당됩니다. 공식 문서는 이 점에 대해 명시적으로 설명합니다. 복잡한 쿼리는 여러 작업을 병렬로 시작할 수 있고 여러 세션이 동시에 동일한 작업을 수행할 수 있으므로 실제로 사용되는 메모리는 work_mem(postgresql.org/docs/current/runtime-config-resource.html, 2026년 8월 24일 액세스)의 몇 배 가치가 될 수 있습니다.

기억해야 할 진짜 최악의 사례

서버의 메모리를 위협하는 것은 max_connections × work_mem만이 아닙니다. max_connections × work_mem × 쿼리당 동시 작업 수입니다. 서버가 스왑되거나 max_connections 증가 후 메모리가 부족해지는 현상을 무해하다고 설명하는 제품입니다.

#
공식

PostgreSQL 위키 크기 조정 공식

공식 PostgreSQL 프로젝트 위키에는 총 열려 있는 연결 수가 아니라 하드웨어가 병렬로 효율적으로 처리할 수 있는 활성 연결 수를 계산하기 위한 벤치마크 공식이 문서화되어 있습니다(wiki.postgresql.org/wiki/Number_Of_Database_Connections, 2026년 8월 24일 액세스).

공식

이상적인 활성 동시성 = (물리적 코어 × 2) + 효율적인 디스크. 코어 수에는 하이퍼스레딩이 제외됩니다. 별도의 물리적 디스크(“스핀들”)라는 개념이 원래 의미를 많이 상실한 최신 SSD 스토리지에서는 유효 디스크의 수가 1에 가깝게 유지됩니다.

8개의 물리적 코어와 SSD 스토리지가 있는 서버에서 공식은 처리량이 저하되기 전에 (8 × 2) + 1 = 17개의 활성 연결을 제공합니다. 이 수치는 종종 놀랍습니다. 실제로 애플리케이션이 여는 수백 개의 연결에 비하면 작은 것처럼 보입니다. 이것이 바로 다음 단락의 주제입니다.

The number calculated by the formula measures the concurrency that the CPU and disk can absorb, not the number of client connections your application needs to open. A fleet of 20 application processes, each with its own pool of 10 connections, opens 200 simultaneous connections to Postgres even if only 17 of them are actively working at any given time. Without a pooler, max_connections must cover the 200, not the 17. It is this gap that pushes most architectures to add a pooler in transaction mode, even if it means choosing which one (see our comparison PgBouncer, Supavisor and PgCat).

#
절차

max_connections를 변경하는 방법(및 재부팅이 필요한 이유)

max_connections는 핫스왑되지 않습니다. 이것은 postmaster 컨텍스트 매개변수입니다. Postgres는 시작 시 이를 한 번 읽어 공유 메모리 크기를 조정합니다. 구성 다시 로드(pg_reload_conf() 또는 SIGHUP)로는 충분하지 않습니다. 서버를 다시 시작해야 합니다.

먼저 현재 값과 해당 컨텍스트를 확인하여 다시 시작해야 하는지 확인하세요.

psqlsql
SHOW max_connections;

SELECT name, setting, context
FROM pg_settings
WHERE name = 'max_connections';

-- context='postmaster'는 재부팅이 필요함을 확인합니다.

그런 다음 새 값을 적용하고 다시 시작합니다.

psqlsql
ALTER SYSTEM SET max_connections = '300';

-- postgresql.auto.conf에 작성되었습니다.
-- Postgres를 다시 시작할 때까지는 아무런 효과가 없습니다.
terminalbash
# 체계적으로
sudo systemctl restart postgresql

# systemd 없이 pg_ctl을 사용하여 직접
pg_ctl restart -D $PGDATA -m fast
많은 사람들이 잊어버리는 마진

max_connections에는 기본적으로 superuser_reserved_connections(기본적으로 3)가 포함됩니다. 이러한 연결은 포화 시 수퍼유저를 위해 예약되어 있으며 글로벌 카운터에 아직 도달하지 않은 경우에도 애플리케이션에서 사용할 수 없습니다.

#
체크인된 코드

Aurabase가 Postgres 클러스터에서 max_connections 예산을 책정하는 방법

max_connections 크기 조정은 단순한 이론적인 연습이 아닙니다. Aurabase가 관리형 Postgres 클러스터에 예산을 책정하는 방법은 다음과 같습니다.

100
포스트그레스 기본값
튜닝 전 max_connections
50→400
전용 AURABASE 베어링
CNPG 클러스터를 통해 기업에 무료로 제공
3
슈퍼유저가 예약되었습니다
superuser_reserved_connections, Postgres 기본값

전용 클러스터: 프로젝트당 Postgres 클러스터 1개

이 수준에서( 전용 및 공유 기반비교 참조) 각 프로젝트는 인스턴스 크기에 맞는 자체 CloudNativePG 클러스터와 자체 max_connections 예산을 받습니다.

무료 (전용)max_connections 50인스턴스 1개 · vCPU 5억개 · 512Mi
프로(기본값)max_connections 200인스턴스 2개 · vCPU 1개 · 2Gi
팀max_connections 300인스턴스 3개 · vCPU 2개 · 3Gi
사업max_connections 400인스턴스 3개 · vCPU 2개 · 4Gi

공유 클러스터: 조직의 여러 프로젝트, 공유 예산

이 두 번째 경로에서는 동일한 조직의 모든 프로젝트가 공유 기본 프로젝트 앞에서 CNPG 풀러(PgBouncer, transaction모드)를 통해 연결됩니다.

무료max_connections 50max_client_conn 100max_user_connections 20
프로max_connections 100max_client_conn 200max_user_connections 60
팀max_connections 200max_client_conn 400max_user_connections 150

조직의 모든 프로젝트는 공유 애플리케이션 역할을 통해 연결됩니다. 따라서 max_user_connections만으로도 이 역할이 전체 클러스터에서 열 수 있는 총 서버 연결을 제한합니다. 이는 풀러 자체에 대한 클라이언트 연결만 제한하는 max_client_conn가 아닌 실제 클러스터 전역 보호 장치입니다.

그러나 이 풀러는 SDK 애플리케이션 트래픽만 제공합니다. PostgREST는 기본(-rw서비스)에 직접 연결된 상태로 유지됩니다. 트랜잭션 모드에서 풀링하면 pgrst라는 전용 LISTEN 채널을 수신하는 스키마 재로드 메커니즘이 중단됩니다. 따라서 자체 연결(공유 수준의 복제본당 2개, 전용 수준의 복제본당 10개)은 풀러 외부에 있는 기본의 max_connections 예산에서 직접적으로 아래 절차의 1단계에 포함되어야 하는 "잊혀진" 연결 종류로 직접 계산됩니다.

현재 교정 중인 수치(그렇다고 가정함)

코드는 이러한 공유 풀러 예산을 게시된 벤치마크의 고정 수치가 아닌 로드 상태에서 pg_stat_activity를 측정하여 실제 조건에서 보정할 시작 값으로 명시적으로 문서화합니다. 이는 벤치마크 방법론에 설명된 것과 동일한 원칙입니다. 조정하기 전에 측정하고 추측하지 말고 희망하세요. 이러한 클러스터는 Postgres 16 대 17 대 18비교에 문서화된 선택 사항인 PostgreSQL 16에서 실행됩니다.

#
방법

풀링 없이 max_connections 크기를 조정하는 5단계 절차

이 절차는 특정 도구에 의존하지 않으며 관리되거나 자체 호스팅되는 모든 Postgres 서버에 적용됩니다.

  1. 실제 클라이언트 연결을 계산합니다. 내부 풀의 크기와 관리 도구, 복제 및 모니터링을 곱한 애플리케이션 프로세스 수입니다. max_connections 층을 설정하는 것은 공식이 아니라 이 숫자입니다.
  2. PostgreSQL 위키의 공식(물리적 코어 × 2) + 효율적인 디스크를 사용하여 하드웨어의 이상적인 동시성을 계산하십시오. 이 그림은 처리량을 저하시키지 않고 실제로 병렬로 작동할 수 있는 연결 수를 나타냅니다.
  3. superuser_reserved_connections 및 애플리케이션 외부에서 자체 연결을 여는 모든 관리 도구에 대한 여유를 두고 1단계의 실제 요구 사항 이상으로 max_connections를 설정합니다.
  4. ALTER SYSTEM SET을 사용하여 변경 사항을 적용한 다음 서버를 다시 시작합니다. 이것은 postmaster 매개변수입니다. 위에서 자세히 설명했듯이 간단한 다시 로드만으로는 충분하지 않습니다.
  5. 시간 경과에 따른 pg_stat_activity를 모니터링합니다. 유휴 연결 수가 활성 연결 수를 크게 초과하는 경우 이는 max_connections 문제가 아닙니다. 이는 더 높은 수가 아니라 서버 앞에 풀러가 필요하다는 신호입니다.

5단계의 모니터링 요청은 직접 사용할 수 있습니다.

psqlsql
SELECT state, count(*)
FROM pg_stat_activity
GROUP BY state
ORDER BY count(*) DESC;
#
경고 신호

공식이 더 이상 충분하지 않을 때: 풀러가 필요하다는 신호

값에 관계없이 max_connections만으로는 더 이상 충분하지 않을 때 세 가지 신호가 체계적으로 반환됩니다.

  1. FATAL: sorry, too many clients already 오류는 최대 로드 중에 나타나는 반면 pg_stat_activity에 표시된 대부분의 연결은 유휴 상태입니다.
  2. 애플리케이션은 서버리스 환경이나 임시 작업자(에지 기능, 단기 작업)에서 실행되며 Postgres의 연결당 프로세스 모델이 수용하도록 설계된 것보다 훨씬 빠르게 연결을 열고 닫습니다.
  3. 위의 공식과 절차는 이미 적용되었으며 클라이언트 연결에 대한 실제 요구는 work_mem 또는 shared_buffers를 위험에 빠뜨리지 않고 할당할 수 있는 사용 가능한 메모리를 계속 초과하고 있습니다.

이 세 가지 경우에서 정답은 거의 항상 더 높은 max_connections가 아니라 애플리케이션과 Postgres 사이에 위치한 풀러입니다. 비교 PgBouncer, Supavisor 및 PgCat에서는 세 가지 옵션을 자세히 설명하고 트랜잭션 모드 가이드에서는 풀러가 설치된 후 가장 일반적인 절충안을 설명합니다. 연결 이상의 모든 Postgres 조정에 대해서는 프로덕션 Postgres 조정 체크리스트를 참조하세요.

#
자주 묻는 질문

자주 묻는 질문

PostgreSQL의 기본 max_connections는 무엇입니까?+
100, 기본적으로 수퍼유저용으로 예약된 연결 3개(superuser_reserved_connections) 이 기본값은 풀러를 통과하는 많은 애플리케이션에 적합하지만, 애플리케이션 프로세스 집합이 각각 자체 연결 배치를 열자마자 풀링 없이는 금방 부족해집니다.
PostgreSQL을 다시 시작하지 않고 max_connections를 변경할 수 있습니까?+
아니요. max_connections는 포스트마스터 컨텍스트 매개변수입니다. Postgres는 시작 시 이를 한 번 읽어 공유 메모리 크기를 조정합니다. ALTER SYSTEM SET은 postgresql.auto.conf에 새 값을 쓰지만 전체 서버를 다시 시작할 때만 적용됩니다. 새로고침이나 SIGHUP만으로는 충분하지 않습니다.
유휴 PostgreSQL 연결은 얼마나 많은 메모리를 소비합니까?+
단일 공식 번호는 없습니다. work_mem, shared_buffers 및 세션당 로드되는 확장에 따라 다릅니다. 그러나 문서화된 내용은 work_mem이 연결별이 아닌 쿼리의 정렬 또는 해싱 작업별로 할당된다는 것입니다. 따라서 단일 복잡한 쿼리는 단일 활성 연결에서 work_mem을 여러 번 사용할 수 있습니다.
항상 더 높은 max_connections보다 PgBouncer와 같은 풀러를 선호해야 합니까?+
대부분의 경우 그렇습니다. 실제 클라이언트 연결 수가 PostgreSQL 위키 공식으로 계산된 이상적인 동시성을 크게 초과하면 그렇습니다. 트랜잭션 모드 풀러는 애플리케이션 측에서 훨씬 더 많은 수의 논리적 연결 사이에서 적은 수의 물리적 연결을 풀링합니다. PgBouncer, Supavisor 및 PgCat 비교를 참조하여 어느 것을 선택하십시오.
공식(코어 × 2) + 효율적인 디스크는 정확히 무엇을 측정합니까?+
이상적인 활성 동시성, 즉 주어진 서버의 CPU와 디스크가 처리량을 저하시키지 않고 병렬로 처리할 수 있는 요청 수를 추정하며, max_connections에서 열려는 총 연결 수가 아닙니다. 이는 엄격한 제한이 아닌 공식 PostgreSQL 프로젝트 위키에 문서화된 측정을 통해 검증되는 시작점입니다.
내 Postgres 서버가 연결 제한에 가까워졌는지 어떻게 알 수 있나요?+
pg_stat_activity를 쿼리하고 활성 상태의 연결 수와 유휴 상태의 연결 수를 비교합니다. max_connections 한도 근처에 많은 수의 유휴 연결이 있고 그 뒤에 활성 요청이 없으면 거의 항상 max_connections를 더 늘릴 필요가 아니라 풀링이 필요함을 나타냅니다.

배포할 준비가 되셨나요?

5분 만에 백엔드를 완성하세요.

신용카드 불필요 · 500MB 무료 · 50,000 MAU