1.3 프로세스 모델
PostgreSQL은 프로세스 기반(process-per-connection) 아키텍처를 채택합니다. MySQL/InnoDB·MS SQL Server 같은 스레드 모델과 달리, 클라이언트 한 명마다 OS 레벨의 별도 프로세스가 생성됩니다. 그 위에 백그라운드 일을 담당하는 보조 프로세스 묶음이 항상 떠 있습니다. 본 절에서는 클러스터 한 개를 띄울 때 실제로 어떤 프로세스 가족이 만들어지는지 정리합니다.
프로세스 모델
flowchart TD
PM["<b>postmaster</b><br/>(parent, listener)"]
PM --> CKPT["<b>checkpointer</b><br/>dirty page → disk"]
PM --> BGW["<b>background writer</b><br/>dirty page 점진적 flush"]
PM --> WALW["<b>WAL writer</b><br/>WAL buffer → pg_wal"]
PM --> AVL["<b>autovacuum launcher</b>"]
PM --> ARCH["<b>archiver</b><br/>WAL → archive (선택)"]
PM --> LR["<b>logical replication launcher</b>"]
AVL -.fork.-> AVW["autovacuum worker × N"]
LR -.fork.-> LRW["logical replication worker × N"]
PM -. 클라이언트 접속 .-> BE1["<b>backend</b> #1"]
PM -. 클라이언트 접속 .-> BE2["<b>backend</b> #2"]
PM -. 클라이언트 접속 .-> BEN["<b>backend</b> #N"]
PM --> WS["<b>walsender</b><br/>standby로 WAL 스트림"]
classDef root fill:#ede9fe,stroke:#6d28d9,color:#3b0764,stroke-width:2px
classDef aux fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
classDef be fill:#fef3c7,stroke:#b45309,color:#78350f
classDef rep fill:#d1fae5,stroke:#047857,color:#064e3b
class PM root
class CKPT,BGW,WALW,AVL,ARCH,LR,AVW,LRW aux
class BE1,BE2,BEN be
class WS rep
postmaster — 부모 프로세스
클러스터를 기동하면 postgres라는 바이너리가 postmaster 역할로 시작합니다. 한 클러스터에는 postmaster가 정확히 한 개 있고, 모든 다른 프로세스의 부모입니다.
postmaster의 책임:
- TCP 포트·Unix 도메인 소켓을 열고
listen() - 새 클라이언트 연결이 오면
fork()해서 backend 프로세스 생성 - 보조 프로세스(checkpointer, WAL writer 등) 기동·감시·재시작
- 자식 프로세스가 비정상 종료되면 클러스터 전체를 안전하게 재기동(crash recovery 트리거)
postmaster 자체는 SQL을 실행하지 않습니다. 감시·중재 역할만 합니다.
backend — 클라이언트 1명당 1개
PostgreSQL은 클라이언트 접속마다 postmaster가 fork()해서 backend 프로세스를 한 개 만든다. backend는 그 클라이언트의 모든 SQL을 처리하고, 연결이 끊기면 종료됩니다.
sequenceDiagram
participant Client
participant Postmaster
participant Backend
Client->>Postmaster: TCP connect (포트 5432)
Postmaster->>Postmaster: 인증 검사 (pg_hba.conf)
Postmaster->>Backend: fork()
Postmaster-->>Client: backend 핸드오프 완료
Note over Client,Backend: 이후 클라이언트와 backend가<br/>postmaster 개입 없이 직접 통신
Client->>Backend: SQL
Backend-->>Client: 결과
Client->>Backend: 연결 종료
Backend->>Backend: exit
이 모델의 함의:
| 특성 | 결과 |
|---|---|
| 한 연결 = 한 프로세스 | OS 프로세스가 무겁기 때문에 동시 접속이 많아지면 (수백~수천) 메모리·컨텍스트 스위칭 비용 급증 |
| 격리도 높음 | 한 backend의 crash가 다른 backend에 직접 영향 주지 않음 — postmaster가 감시 |
| 커넥션 풀 사실상 필수 | 운영에서는 pgBouncer·pgcat·pgpool 등을 앞에 둔다 (Part XIII 커넥션 풀링 참고) |
보조 프로세스 (utility processes)
postmaster가 띄우는 보조 프로세스는 대부분 클러스터당 1개씩만 존재합니다.
| 프로세스 | 역할 |
|---|---|
| checkpointer | 주기적으로 체크포인트 수행. shared_buffers의 dirty page를 디스크에 flush, WAL을 안전하게 잘라낼 수 있는 시점 생성 |
| background writer | 체크포인트와 별개로 dirty page를 점진적 flush. checkpointer 부담과 I/O 스파이크를 완화 |
| WAL writer | WAL buffer 내용을 pg_wal/의 세그먼트 파일로 flush. backend가 commit 시 동기 flush를 기다리는 시간을 줄임 |
| autovacuum launcher | autovacuum worker를 만들 시점을 결정. 통계 기반으로 vacuum/analyze 대상 데이터베이스를 결정한 뒤 worker를 fork |
| autovacuum worker | launcher가 띄우는 단기 워커. 실제 VACUUM/ANALYZE 작업 수행. 동시 실행 수는 autovacuum_max_workers로 제한 |
| archiver | archive_mode = on일 때만 동작. 완료된 WAL 세그먼트를 archive_command로 외부 위치에 복사 |
| logical replication launcher | 로지컬 복제 구독자 측에서 동작. 각 subscription마다 logical replication worker(apply worker)를 fork |
| logical replication worker | publication의 변경을 받아 로컬에 적용. 트랜잭션 단위 또는 streaming 단위로 작동 |
| walsender | primary 측에서 standby/구독자에게 WAL을 스트리밍. replication 연결 하나당 walsender 한 개 |
| walreceiver | standby 측에서만 동작. primary의 walsender로부터 WAL을 받아 로컬 pg_wal/에 쓴다 |
| startup process | 서버 기동 직후 또는 복구 중에만 존재. WAL을 재생해 일관된 상태로 만든 뒤 종료(primary) 또는 계속 재생(standby) |
사라진 stats collector
PostgreSQL 14까지는 stats collector라는 별도 프로세스가 UDP로 통계를 모았습니다. v15부터 이 프로세스는 사라지고 cumulative statistics system이 shared memory 기반으로 동작합니다. backend가 자기 통계를 shared memory에 직접 쓰고, 종료 시점에 pg_stat/ 디렉토리에 영구화합니다. v15+에서 ps 출력에 stats collector가 보이지 않는 이유입니다.
실제로 보기 — ps와 pg_stat_activity
기동된 클러스터의 프로세스 가족은 OS 도구로 볼 수 있습니다.
# Linux
ps -ef --forest | grep '[p]ostgres'전형적인 출력 (PostgreSQL 17, 클라이언트 2명 접속 중, standby 1대 연결):
postgres 1024 1 /usr/pgsql-17/bin/postgres -D /var/lib/pgsql/17/data
postgres 1025 1024 \_ postgres: logger
postgres 1027 1024 \_ postgres: checkpointer
postgres 1028 1024 \_ postgres: background writer
postgres 1029 1024 \_ postgres: walwriter
postgres 1030 1024 \_ postgres: autovacuum launcher
postgres 1031 1024 \_ postgres: logical replication launcher
postgres 2001 1024 \_ postgres: app_user app_main 10.0.0.5(43210) idle
postgres 2002 1024 \_ postgres: app_user app_main 10.0.0.6(43211) SELECT
postgres 2100 1024 \_ postgres: walsender repl_user 10.0.0.10(5432) streaming 0/3A001F8backend의 process title에는 <user> <db> <client_ip>(<port>) <state> 형식으로 현재 상태가 박혀 있습니다. ps만 봐도 누가 무얼 하고 있는지 대략 파악됩니다.
SQL 레벨에서는 pg_stat_activity 뷰가 같은 정보를 카탈로그로 제공합니다.
SELECT pid, backend_type, datname, usename, client_addr, state, query
FROM pg_stat_activity
ORDER BY pid;backend_type 컬럼은 위 표의 프로세스 종류를 그대로 노출한다 — 'client backend', 'checkpointer', 'autovacuum worker', 'walsender', 'logical replication worker' 등.
프로세스 수 제한 파라미터
기본값 기준으로 한 클러스터의 총 프로세스 수는 다음 설정의 합에 가깝습니다.
| 설정 | 기본값 | 의미 |
|---|---|---|
max_connections | 100 | 동시 client backend 수 상한 |
superuser_reserved_connections | 3 | 슈퍼유저 예약분 |
max_worker_processes | 8 | autovacuum·logical replication·parallel query·확장 worker 총합 상한 |
autovacuum_max_workers | 3 | 동시 autovacuum worker 수 |
max_wal_senders | 10 | 동시 walsender 수 (복제·로지컬 구독자) |
max_logical_replication_workers | 4 | logical replication worker 수 |
max_parallel_workers | 8 | parallel query 워커 풀 |
운영 환경에서 동시 접속 1000명을 받겠다면 max_connections = 1000처럼 키워야 하지만, OS 프로세스가 천 개로 늘면 커널 스케줄러·메모리 압박이 커집니다. 운영 권장은 max_connections를 200~500 정도로 제한하고, 그 앞에 pgBouncer 같은 풀러를 두는 것입니다.
max_connections·max_worker_processes·max_wal_senders 등은 shared memory 크기에 영향을 주므로 변경 시 클러스터 재시작이 필요합니다. ALTER SYSTEM으로 값만 바꾸고 reload하면 적용되지 않습니다.crash 시 동작
backend 중 하나가 SIGSEGV 등으로 비정상 종료되면, postmaster는 클러스터 전체를 강제로 셧다운한 뒤 자동 재기동합니다. 이유는 안전성 — 죽은 backend가 shared memory를 망가뜨렸을 가능성을 배제할 수 없기 때문입니다. 재기동 시 startup process가 WAL을 재생해 일관된 상태를 복원합니다.
운영자가 알아 둘 것:
- 한 클라이언트의 query가 backend crash를 유발하면 다른 모든 클라이언트도 끊긴다
- 끊긴 직후 클러스터는 recovery 상태가 되며 수 초~수십 초 동안 새 연결을 받지 못할 수 있다
- 자주 발생하면 원인(특정 확장, 메모리 부족, 손상된 데이터)을 추적해야 한다 — 그냥 무시하면 안 된다
정리
- PostgreSQL은 프로세스 기반 모델 — 클라이언트 1명당 backend 프로세스 1개
- postmaster가 부모. 보조 프로세스(checkpointer, WAL writer, autovacuum launcher 등)를 띄우고 감시
- v15부터 stats collector가 사라지고 cumulative statistics system이 shared memory로 동작
- 동시 접속이 많은 시스템은 pgBouncer 같은 풀러가 사실상 필수
pg_stat_activity.backend_type으로 SQL에서 프로세스 종류 식별 가능- 한 backend의 crash는 클러스터 전체를 자동 재기동시킨다
다음 절(1.4)에서는 이 프로세스들이 공유하는 메모리 영역(shared_buffers, work_mem, WAL buffer)을 봅니다.