본문 바로가기
데이터베이스/PostgreSQL 내부 구조

PostgreSQL 기본 (0) — 연결과 프로세스 구조

by 조민서 2026. 4. 18.

쿼리가 실행되기까지 "클라이언트 → 서버" 사이에서 일어나는 과정과
PostgreSQL의 프로세스 모델과 데이터 흐름을 정리한다.

 

PostgreSQL은 프로세스 기반이다

PostgreSQL은 멀티스레드가 아니라 멀티프로세스 구조다. 클라이언트 연결 하나당 OS 프로세스 하나가 붙는다. 이 구조의 중심에 있는 것이 Postmaster다.


Postmaster — 모든 프로세스의 부모

PostgreSQL 서버를 시작하면 가장 먼저 뜨는 프로세스가 Postmaster이며 역할은 세가지다.

  1. listen: 설정된 주소와 포트(기본 5432)에서 클라이언트 연결 요청을 대기
  2. fork: 연결 요청이 들어오면 새 백엔드 프로세스를 fork
  3. mangement: 백그라운드 프로세스(bgwriter, checkpointer, autovacuum 등)를 띄우고 관리. 백엔드 프로세스가 크래시되면 shared memory를 리셋하고 복구

Postmaster는 쿼리를 처리하지 않는다. 연결을 받고, 자식 프로세스를 만들고, 살아 있는지 감시하는 것이 전부다.


PostgreSQL 연결 과정

클라이언트(psql, 애플리케이션, ORM 등)가 PostgreSQL에 접속할 때 일어나는 일을 순서대로 보면 이렇다.

핵심: Postmaster가 fork한 뒤, 클라이언트는 Postmaster가 아니라 fork된 백엔드 프로세스와 직접 통신한다. Postmaster는 다음 연결을 기다리러 돌아간다.


백엔드 프로세스 — 연결 하나 = 프로세스 하나

fork된 백엔드 프로세스는 해당 클라이언트 연결이 끊길 때까지 살아 있으면서, 그 연결의 모든 쿼리를 처리한다. 위 다이어그램에서 "Backend Process (PID: 12345)"에 해당하는 부분이다.
 
백엔드 프로세스 안에는 두 가지 영역이 있고, 바깥에 하나가 더 있다.
 

Private Memory — 이 프로세스만 쓰는 메모리

각 백엔드 프로세스는 자기만의 메모리 공간을 가진다. 다른 프로세스와 공유하지 않는다.

영역 용도 기본 값
work_mem 정렬, 해시 조인, Bitmap 연산에 사용. 쿼리당 여러 번 할당될 수 있음 4MB
maintenance_work_mem VACUUM, CREATE INDEX 같은 유지보수 작업에 사용 64MB
temp_buffers 임시 테이블 전용 캐시 8MB

work_mem은 "프로세스당"이 아니라 "정렬이나 해시 연산 한 번당" 할당된다. 복잡한 쿼리 하나가 정렬을 3번 하면 work_mem × 3이 쓰일 수 있다. 연결 100개가 동시에 이런 쿼리를 돌리면 메모리가 빠르게 차니, 무작정 올리면 안 된다.
 

State — 트랜잭션과 세션 상태

각 백엔드는 자기만의 트랜잭션 상태를 유지한다.

  • Transaction ID / Snapshot: 현재 트랜잭션의 ID, 2편에서 다룰 MVCC 스냅샷(xmin, xmax, xip[])
  • Session Variables: SET 명령으로 설정한 세션 변수들 (work_mem, search_path, timezone 등)

이 상태들은 프로세스가 살아 있는 동안 유지되고, 연결이 끊기면 사라진다. 커넥션 풀러를 쓸 때 세션 변수가 다음 클라이언트에게 남지 않도록 주의해야 하는 이유다.
 

Shared Memory — 모든 프로세스가 공유하는 메모리

다이어그램 아래쪽의 Shared Memory는 Postmaster가 서버 시작 시 한 번 초기화하고, 모든 백엔드와 백그라운드 프로세스가 함께 접근하는 영역이다.

영역 역할 관련 시리즈
Shared Buffers 디스크의 8KB(기본 값) 페이지를 캐싱. 읽기/쓰기 모두 여기를 거침 1편
WAL Buffers WAL 레코드를 디스크에 쓰기 전 모아두는 버퍼 5편
Lock Table 테이블 락 정보 관리 (행 락은 여기가 아니라 튜플 헤더에 저장) 3편

백엔드 프로세스가 쿼리를 실행할 때, 필요한 페이지가 Shared Buffers에 있으면 바로 쓰고(cache hit),
없으면 디스크에서 읽어 Shared Buffers에 올린다. 한 백엔드가 올린 페이지를 다른 백엔드가 바로 쓸 수 있다 — 공유 메모리니까.
 
pg_stat_activity에서 보이는 각 행이 바로 백엔드 프로세스 하나에 대응한다.

SELECT pid, state, query, backend_type
FROM pg_stat_activity
WHERE backend_type = 'client backend';

  pid  |        state        |          query          | backend_type
-------+---------------------+-------------------------+----------------
 12345 | active              | SELECT * FROM orders... | client backend
 12346 | idle                |                         | client backend
 12347 | idle in transaction |                         | client backend

 


연결 하나 = 프로세스 하나 구조

연결 하나 = 프로세스 하나라는 설계는 간단하고 안전하지만, 비용이 있다.

  • 메모리: 백엔드 프로세스 하나당 기본 수 MB의 메모리를 차지한다. max_connections = 1000이면 그만큼의 프로세스가 뜰 수 있다.
  • fork 비용: 새 연결마다 OS 프로세스를 fork하니, 연결/해제가 잦은 워크로드에서는 오버헤드가 된다.
  • 프로세스 격리: 한 백엔드가 크래시해도 다른 백엔드에 직접적 영향이 없다.

그래서 운영 환경에서는 Process Connection Pool을필수로 쓴다.


Connection Pool — 연결을 재사용한다

PgBouncer 같은 커넥션 풀러는 클라이언트와 PostgreSQL 사이에 앉아서, 적은 수의 PostgreSQL 연결을 여러 클라이언트가 돌려 쓰게 해준다.

PgBouncer: Connection Pool

클라이언트가 트랜잭션을 마치면 그 연결은 풀에 반환되고, 다른 클라이언트가 가져다 쓴다. PostgreSQL 입장에서는 프로세스 20개만 관리하면 된다.


백그라운드 프로세스들

백그라운드 프로세스 종류

 
Postmaster는 클라이언트 백엔드 외에도 시스템 운영에 필요한 백그라운드 프로세스들을 띄운다.

프로세스역할관련 시리즈
Background Writer (bgwriter)dirty 페이지를 주기적으로 디스크에 쓴다. 체크포인트 시 I/O 급증을 줄이는 역할5편 WAL
Checkpointer체크포인트를 수행. 모든 dirty 페이지를 flush하고 WAL에 체크포인트 레코드 기록5편 WAL
WAL WriterWAL 버퍼를 주기적으로 디스크에 flush5편 WAL
Autovacuum Launcherautovacuum worker를 필요에 따라 띄움4편 VACUUM
Autovacuum Worker실제 VACUUM/ANALYZE 수행4편 VACUUM
Stats Collector테이블/인덱스 통계 수집 (pg_stat_* 뷰에 반영)7편 Optimizer
WAL Sender / Receiver스트리밍 복제 시 WAL을 전송/수신5편 WAL

 
전부 Postmaster의 자식 프로세스이고, ps 명령으로 확인할 수 있다.

ps aux | grep postgres

postgres  1234  postmaster
postgres  1235  checkpointer
postgres  1236  background writer
postgres  1237  walwriter
postgres  1238  autovacuum launcher
postgres  1239  stats collector
postgres  1240  client backend    ← 클라이언트 연결
postgres  1241  client backend

데이터 흐름 — 쿼리 과정

백엔드 프로세스가 SQL 쿼리를 받으면, 아래 경로를 거쳐 데이터를 가져온다.

이 흐름이 1편(페이지, shared buffers)과 5편(WAL, checkpoint)의 큰 그림이다.