PostgreSQL 연결 수와 PgBouncer의 역할

여러 서버의 연결을 적은 데이터베이스 연결로 공유하는 풀
목차

애플리케이션 서버를 증설하면 데이터베이스 연결 수도 늘어날 수 있습니다. 여러 서버가 같은 PostgreSQL에 연결한다면, 운영자는 프로세스별 연결 풀의 최대 크기를 합산해야 합니다. 이 합이 데이터베이스의 연결 제한을 넘으면 서버를 늘린 뒤에도 연결 오류가 발생할 수 있습니다.

연결 풀은 요청마다 연결을 새로 만드는 대신 기존 연결을 빌려주고 돌려받는 구조입니다. 애플리케이션 프로세스마다 풀이 따로 존재하면 전체 연결 수는 프로세스 수에 따라 늘어납니다. Rakesh K의 PgBouncer 설명도 이 연결 수 문제를 다룹니다.

프로세스 수와 연결 상한

서버 네 대에서 각각 애플리케이션 프로세스 하나를 실행하고, 프로세스별 풀이 최대 100개의 연결을 만들도록 설정했다고 가정하면 연결 상한은 400개입니다. 백그라운드 작업과 관리 도구가 사용하는 연결은 여기에 추가됩니다. 배포 중 새 서버와 기존 서버가 동시에 실행되는 시간도 고려해야 합니다.

애플리케이션 최대 연결 수
= 실행 중인 프로세스 수 × 프로세스별 풀의 최대 크기

이 식은 모든 프로세스의 풀 크기가 같을 때 적용합니다. 크기가 다르면 각 풀의 최대 크기를 합산합니다. 계산 결과는 실제 사용량이 아니라 상한입니다. 평소에는 적게 사용하더라도 요청이 몰리면 상한에 가까워질 수 있으므로, 데이터베이스의 연결 제한과 현재 사용량, 풀에서 기다리는 요청을 함께 봅니다.

PostgreSQL은 연결마다 서버 프로세스를 사용합니다. 연결이 늘면 메모리와 운영체제 자원도 필요합니다. 연결 하나의 비용을 고정된 숫자로 계산하기는 어렵습니다. 쿼리와 설정에 따라 다르므로 “100개면 항상 1GB” 같은 수치를 운영 기준으로 삼기보다 현재 환경을 측정해야 합니다.

트랜잭션 풀의 연결 사용과 반환

트랜잭션 풀을 설명하는 직접 작성 예시입니다. 클라이언트 연결은 유지되지만 서버 연결은 트랜잭션 종료 후 풀에 반환될 수 있습니다.

PgBouncer가 공유하는 실제 DB 연결

PgBouncer는 애플리케이션과 PostgreSQL 사이에 놓는 연결 풀러입니다. 여러 클라이언트 연결이 더 적은 수의 데이터베이스 연결을 이용하도록 조정합니다. 애플리케이션 내부의 풀과 목적이 일부 겹치지만, 여러 애플리케이션 프로세스가 공통으로 접근하는 지점에서 연결을 관리한다는 차이가 있습니다.

트랜잭션 풀링에서는 PgBouncer가 트랜잭션이 진행되는 동안 서버 연결을 배정하고, 끝나면 풀에 돌려놓습니다. 다음 트랜잭션은 다른 서버 연결을 받을 수 있습니다. 요청 사이에 오래 쉬는 클라이언트가 서버 연결을 계속 차지하는 상황을 줄일 수 있습니다.

PgBouncer는 유휴 클라이언트가 차지하는 서버 연결을 줄일 수 있지만, 데이터베이스의 쿼리 처리 능력을 늘리지는 않습니다. 느린 쿼리가 연결을 오래 붙잡으면 대기 요청이 늘어납니다. 풀 크기를 줄였을 때 대기 시간이 얼마나 늘어나는지 측정하고, 긴 쿼리와 트랜잭션도 조사해야 합니다.

트랜잭션 사이에 남는 세션 상태

트랜잭션마다 다른 연결을 받을 수 있으므로 한 연결에 남겨둔 상태를 다음 트랜잭션에서 다시 읽는 코드는 주의해야 합니다. 세션 수준 설정, 임시 테이블의 사용 방식, 세션 수준 advisory lock 등이 검토 대상입니다. advisory lock은 애플리케이션이 협력해 사용하는 잠금이며, 세션용과 트랜잭션용의 수명이 다릅니다.

prepared statement는 미리 준비한 SQL 문을 재사용하는 기능입니다. PgBouncer FAQ에 따르면 1.21부터 트랜잭션 풀링에서 프로토콜 수준의 이름 있는 prepared statement를 추적할 수 있습니다. 이 기능을 사용하려면 max_prepared_statements가 0보다 커야 합니다. 사용 버전과 드라이버의 동작도 확인해야 합니다. SQL 명령 PREPARE는 별개이며, 지원 조건은 풀링 모드별 기능 표에서 확인할 수 있습니다.

연결 풀러를 도입할 때는 실제 ORM이나 드라이버로 트랜잭션과 재사용을 검사합니다. 정상 조회 한 번만 성공한 것으로 세션 의존성이 없다고 판단할 수는 없습니다.

연결 제한을 높이기 전의 조사

max_connections를 바꾸기 전에 프로세스별 풀 크기와 전체 연결 상한을 계산합니다. 이후 활성 연결, 대기 시간, 긴 트랜잭션, 데이터베이스 자원 사용량을 확인합니다. 유휴 클라이언트가 서버 연결을 많이 차지한다면 트랜잭션 풀링을 검토합니다. 실행 중인 쿼리가 이미 CPU나 디스크를 소모하고 있다면 쿼리와 자원 문제도 해결해야 합니다.

조사 기록에는 프로세스별 풀 크기, 활성 연결 수, 연결을 기다린 시간, 긴 트랜잭션을 남깁니다. 서버를 증설할 때는 변경된 프로세스 수로 연결 상한을 다시 계산하고, 증설 전후의 대기 시간을 비교합니다.

댓글

0

아직 공개된 댓글이 없습니다.