PostgreSQL 확장성 향상: PgBouncer 연결 풀링 구현
PgBouncer를 사용하여 PostgreSQL 연결 오버헤드를 줄이고, 풀링 모드를 선택하며, 풀 크기를 조정하고, 클라이언트 부하를 모니터링하는 방법을 알아봅니다.
PostgreSQL 확장성 향상: PgBouncer 연결 풀링 구현
PostgreSQL은 클라이언트 연결당 하나의 백엔드 프로세스를 사용합니다. 이 모델은 안정적이지만, 웹 애플리케이션이 수백 또는 수천 개의 유휴 연결을 열 때 비용이 많이 듭니다.
PgBouncer는 애플리케이션과 PostgreSQL 사이에 위치하여 더 작은 서버 연결 풀을 유지하고 여러 클라이언트가 이를 재사용할 수 있도록 합니다. 그 결과 연결 오버헤드가 줄어들고 데이터베이스 메모리 사용량을 더 예측 가능하게 만듭니다.
병목 현상: 네이티브 PostgreSQL 연결 오버헤드
PostgreSQL은 연결당 전용 프로세스 모델을 사용합니다. 매우 안정적이고 격리를 보장하지만, 이 아키텍처는 부하가 걸릴 때 상당한 오버헤드를 발생시킵니다.
- 리소스 소비: 새로운 연결마다 서버가 새로운 백엔드 프로세스를 포크해야 하므로 메모리와 CPU 리소스를 소비합니다. 수백 또는 수천 개의 유휴 연결이 불필요하게 RAM을 점유합니다.
- 느린 연결 설정: 새 연결을 설정하려면 네트워크 핸드셰이크, 인증 및 프로세스 초기화가 필요하므로, 특히 연결을 자주 열고 닫는 애플리케이션 요청에 지연 시간이 추가됩니다.
- 확장 한계: 이러한 리소스 요구 사항은 PostgreSQL 서버가 성능 저하 없이 실제로 처리할 수 있는 동시 연결 수에 실질적인 상한선을 부과합니다.
PgBouncer 소개: 경량 프록시
PgBouncer는 클라이언트 애플리케이션과 PostgreSQL 데이터베이스 서버 사이에 위치하는 경량 프록시 서버 역할을 합니다. 핵심 기능은 PostgreSQL 백엔드에 대한 지속적이고 고정된 수의 열린 연결을 유지하고, 이러한 연결을 풀링하여 일시적인 애플리케이션 클라이언트 요청에 재사용하는 것입니다.
이 접근 방식은 두 가지 중요한 이점을 제공합니다.
- 오버헤드 감소: PostgreSQL 서버는 PgBouncer가 유지하는 고정된 연결 풀만 볼 수 있으므로, 들어오는 클라이언트 요청에 대한 비용이 많이 드는 프로세스-연결 포크 주기가 제거됩니다.
- 처리량 증가: 설정된 연결을 재사용함으로써 PgBouncer는 인증 및 연결 초기화 시간을 최소화하여 애플리케이션 처리량을 크게 높이고 지연 시간을 줄입니다.
PgBouncer 풀링 모드 이해
PgBouncer의 효율성은 선택한 풀링 모드에 크게 좌우됩니다. PgBouncer는 세 가지 기본 모드를 제공하며, 각각 다른 애플리케이션 아키텍처와 동시성 요구에 적합합니다.
1. 세션 풀링 (pool_mode = session)
세션 풀링은 기본적이면서 가장 안전한 모드입니다. 클라이언트가 연결되면 PgBouncer는 클라이언트가 연결을 끊을 때까지 풀링된 서버 연결을 해당 클라이언트에 전용으로 할당합니다. 연결은 클라이언트가 명시적으로 세션을 종료할 때만 풀로 반환됩니다.
- 사용 사례: 준비된 명령문, 임시 테이블, 사용자 정의 변수용
SET명령 등 세션별 기능에 크게 의존하는 애플리케이션. - 장점: 가장 안전하며 모든 PostgreSQL 기능과 완벽하게 호환됩니다.
- 단점: 클라이언트가 유휴 상태인 동안에도 연결이 유지되므로 효율성이 가장 낮습니다.
2. 트랜잭션 풀링 (pool_mode = transaction)
트랜잭션 풀링은 일반적으로 특히 상태 비저장 API를 사용하는 트래픽이 많은 웹 애플리케이션에 권장됩니다. 서버 연결은 단일 트랜잭션(BEGIN부터 COMMIT/ROLLBACK까지) 동안만 클라이언트에 전용으로 할당됩니다. 트랜잭션이 완료되면 연결은 즉시 풀로 반환되어 다른 대기 중인 클라이언트가 재사용할 수 있습니다.
- 사용 사례: OLTP 시스템 및 마이크로서비스에서 흔히 볼 수 있는 짧고 빈번한 트랜잭션.
- 장점: 서버 리소스를 매우 효율적으로 사용합니다.
- 단점: 애플리케이션이 트랜잭션을 신중하게 관리해야 합니다. 세션 수준 상태 변경(예:
SET extra_float_digits = 3)은 트랜잭션 사이에 손실되거나 다른 클라이언트로 누출될 수 있습니다.
트랜잭션 풀링 경고
트랜잭션 풀링에서는 임시 테이블, 세션 수준
SET변경, 세션 어드바이저리 락, 장기 실행 준비된 명령문과 같은 세션 상태를 피하십시오. PgBouncer는 클라이언트 간에 서버 연결을 재설정하지만, 트랜잭션 풀링은 여전히 애플리케이션 호환성 테스트가 필요합니다.
3. 명령문 풀링 (pool_mode = statement)
명령문 풀링은 가장 공격적인 모드입니다. 서버 연결은 단일 명령문 실행 후 풀로 반환됩니다. 이 모드는 다중 명령문 트랜잭션 사용을 효과적으로 방지하며 매우 제한적입니다.
- 사용 사례: 트랜잭션이 명시적으로 금지되거나 필요하지 않은 고도로 특화된 읽기 전용 로드.
- 장점: 연결 재사용을 극대화합니다.
- 단점: 모든 트랜잭션이 중단됩니다. 트랜잭션 사용이 보장되지 않는 환경에만 적합합니다.
PgBouncer 설정 및 초기 구성
1. 설치
PgBouncer는 표준 배포판 저장소에서 사용할 수 있는 경우가 많습니다.
# Debian/Ubuntu
sudo apt update && sudo apt install pgbouncer
# RHEL/CentOS
sudo dnf install pgbouncer
2. 구성 파일
PgBouncer는 주로 일반적으로 /etc/pgbouncer/에 있는 두 개의 구성 파일을 사용합니다.
pgbouncer.ini: 데이터베이스, 풀 제한 및 작동 모드를 정의하는 기본 구성입니다.userlist.txt: PgBouncer가 PostgreSQL 서버에 인증하는 데 사용하는 사용자와 비밀번호를 정의합니다.
3. 사용자 정의 (userlist.txt)
보안상의 이유로 PgBouncer는 PostgreSQL의 pg_authid 테이블을 직접 읽지 않습니다. 인증할 수 있는 사용자를 수동으로 정의해야 합니다. 이 파일을 안전하게 보호하십시오(예: pgbouncer 사용자 소유 및 권한 제한).
"app_user" "md5<md5-hash>"
"admin_user" "another_hash"
일부 인증 설정에서는 일반 텍스트 비밀번호가 가능하지만, PgBouncer 및 PostgreSQL 버전에서 지원하는 경우 해시되거나 더 강력한 인증을 선호하십시오. 레거시 MD5 인증의 경우 저장된 값은 md5와 비밀번호 및 사용자 이름의 MD5 해시(비밀번호만이 아님)입니다.
4. pgbouncer.ini 구성
pgbouncer.ini 파일은 풀러의 동작을 정의합니다. 아래는 트랜잭션 풀링을 사용하는 일반적인 웹 애플리케이션 설정에 맞춰진 예입니다.
[databases]
# 클라이언트 연결 문자열 정의:
# <데이터베이스 이름> = host=<pg_server_ip> port=<pg_port> dbname=<db_name> user=<pgbouncer_auth_user>
myappdb = host=10.0.0.5 port=5432 dbname=productiondb user=pgbouncer_service
[pgbouncer]
; 수신 구성
listen_addr = *
listen_port = 6432
; 인증 구성
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
; 풀링 모드 (애플리케이션 요구 사항에 따라 설정)
pool_mode = transaction
; DISCARD ALL은 세션 풀링의 기본 재설정 쿼리입니다.
; 트랜잭션 풀링에서는 세션 상태에 의존하기 전에 신중하게 테스트하십시오.
server_reset_query = DISCARD ALL
; 연결 제한 및 크기
; PgBouncer에 대한 최대 총 클라이언트 연결 수
max_client_conn = 1000
; PgBouncer가 데이터베이스당 유지하는 최대 연결 수 (풀 크기)
default_pool_size = 20
; 모든 데이터베이스에 걸쳐 풀에서 허용되는 최대 연결 수
max_db_connections = 100
; 풀이 소진되었을 때 예약할 슬롯 수
reserve_pool_size = 5
; 로깅 및 관리
admin_users = postgres, admin_user
stats_users = postgres
모니터링 및 관리
PgBouncer는 pgbouncer라는 가상 데이터베이스를 노출하여 관리자가 실시간으로 풀러의 상태, 통계 및 연결을 모니터링할 수 있도록 합니다. 정의된 admin_users 중 하나를 사용하여 PgBouncer 리스너 포트(예: 6432)에 연결합니다.
psql -p 6432 -U admin_user pgbouncer
주요 관리 명령:
| 명령어 | 설명 | 사용 참고 사항 |
|---|---|---|
SHOW STATS; |
연결 통계(요청, 바이트, 총 기간)를 표시합니다. | 성능 분석에 유용합니다. |
SHOW POOLS; |
구성된 모든 데이터베이스의 풀 상태를 표시합니다. | cl_active, sv_active, sv_idle을 모니터링하십시오. |
SHOW CLIENTS; |
PgBouncer에 연결된 모든 클라이언트 연결을 나열합니다. | |
RELOAD; |
연결을 중단하지 않고 구성을 다시 로드하려고 시도합니다. | |
PAUSE; |
새 쿼리 수신을 중지하고 현재 트랜잭션이 완료될 때까지 기다립니다. | PgBouncer 유지 관리 또는 업그레이드 전에 사용됩니다. |
확장 팁
- 배치: 애플리케이션과 동일한 서버 또는 네트워크에 최적화된 전용 머신에 PgBouncer를 설치하여 애플리케이션과 풀러 간의 지연 시간을 최소화하십시오.
- 풀 크기 조정:
default_pool_size는 합리적인 숫자(종종 10-50)로 설정해야 하며, 이는 일반적으로 PostgreSQL 서버 자체에서 허용되는 연결 수보다 훨씬 낮습니다. 과도한 풀 크기는 풀링의 목적을 무효화합니다. - 클라이언트 제한:
max_client_conn을 사용하여 연결 폭주가 PgBouncer 자체를 압도하는 것을 방지하십시오. 이는 강력한 프론트엔드 스로틀 역할을 합니다.
요점
PgBouncer는 애플리케이션에 수명이 짧거나 유휴 연결이 많을 때 가장 유용합니다. 애플리케이션이 허용할 수 있는 가장 덜 공격적인 풀링 모드를 선택하고, 데이터베이스를 보호할 수 있을 만큼 PostgreSQL 서버 풀을 작게 유지하며, 사용자가 속도 저하를 느끼기 전에 SHOW POOLS;를 통해 대기 중인 클라이언트를 관찰하십시오.