본문으로 건너뛰기
1.4 메모리 아키텍처

1.4 메모리 아키텍처

PostgreSQL의 메모리는 크게 공유 메모리(shared memory)와 각 backend 로컬 메모리로 나뉩니다. 공유 메모리는 postmaster가 기동 시 한 번 할당해 모든 프로세스가 같이 들여다보는 영역이고, 로컬 메모리는 backend·worker가 자기만 쓰는 작업 공간입니다. 그 위에 OS 페이지 캐시가 한 층 더 얹혀, 디스크 I/O를 흡수합니다.

메모리 계층

    flowchart TD
  subgraph OS["OS 메모리"]
    PC["<b>page cache</b><br/>(커널이 관리)"]
    subgraph PGShared["PostgreSQL Shared Memory<br/>postmaster 기동 시 1회 할당"]
      SB["<b>shared_buffers</b><br/>데이터 페이지 캐시"]
      WB["<b>WAL buffers</b><br/>WAL 임시 버퍼"]
      CLOG["CLOG / SLRU 버퍼<br/>(트랜잭션 커밋 상태)"]
      LOCK["lock tables<br/>proc array, predicate lock"]
      RSLOT["replication slots"]
    end
    subgraph Backend["Backend 1 — Local Memory"]
      WM["<b>work_mem</b><br/>정렬·해시 임시"]
      TB["<b>temp_buffers</b><br/>세션 임시 테이블"]
      CC["catalog cache,<br/>plan cache, relcache"]
    end
    subgraph Maint["Maintenance 작업"]
      MWM["<b>maintenance_work_mem</b><br/>CREATE INDEX, VACUUM"]
    end
  end

  classDef shared fill:#ede9fe,stroke:#6d28d9,color:#3b0764,stroke-width:2px
  classDef local fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
  classDef maint fill:#fed7aa,stroke:#c2410c,color:#7c2d12
  classDef os fill:#d1fae5,stroke:#047857,color:#064e3b
  class SB,WB,CLOG,LOCK,RSLOT shared
  class WM,TB,CC local
  class MWM maint
  class PC os
  

공유 메모리

postmaster는 기동 시 단일 mmap/shmem 영역을 할당합니다. 모든 backend·utility 프로세스가 이 영역을 공유합니다.

영역파라미터기본역할
데이터 페이지 캐시shared_buffers128MB테이블·인덱스의 8KB 페이지를 메모리에 유지. 가장 큰 영역
WAL 임시 버퍼wal_buffers-1 (auto, shared_buffers의 1/32, 최대 16MB)commit 전 WAL 레코드를 모아 두는 버퍼
CLOG/SLRU 버퍼(내부)다수트랜잭션 커밋 상태, multixact, subtrans, commit timestamp 등 SLRU 풀
락 테이블max_locks_per_transaction × max_connections64 × 100heavy-weight lock, predicate lock 메타데이터
proc arraymax_connections활성 backend 목록·스냅샷 정보
replication slotsmax_replication_slots10슬롯별 메타데이터

shared_bufferspostmaster 기동 시점에 정해진 크기로 한 번 잡힌다. 운영 중에 늘리거나 줄일 수 없습니다. 변경하려면 postgresql.conf 수정 후 클러스터 재시작이 필요합니다.

shared_buffers 크기 결정

RAM권장 shared_buffers
< 1GB더 보수적 (1015%)
1GB 이상약 25% (PostgreSQL 공식 가이드)
매우 큰 시스템25~40% 정도. 그 이상은 OS page cache와의 이중 캐싱 손해가 커진다

PostgreSQL이 OS page cache에 적극적으로 의존하므로, shared_buffers를 무한정 키우는 게 답이 아닙니다. shared_buffers + OS cache 합쳐서 데이터셋이 들어가는 것이 이상적입니다.

huge pages

Linux 환경에서는 huge_pages = try(기본)·on으로 설정해 2MB(또는 1GB) huge pages를 쓸 수 있습니다.

설정동작
tryhuge page 풀이 부족하면 일반 4KB 페이지로 fallback (기본)
onhuge page 확보 못 하면 기동 실패
off항상 4KB 페이지

이점: TLB miss 감소, 페이지 테이블 메모리 절감합니다. shared_buffers가 수 GB 이상이면 huge pages 권장합니다.

# 사전 작업 — huge page 풀 확보 (예: 2MB 페이지 1024개 = 2GB)
sysctl -w vm.nr_hugepages=1024
echo 'vm.nr_hugepages=1024' >> /etc/sysctl.d/40-postgresql.conf
Transparent Huge Pages(THP) 권장 설정: Linux의 THP는 PostgreSQL과 잘 안 맞습니다. 메모리 stall·CPU 사용량 급증 사례가 알려져 있습니다. 명시적 huge_pages를 쓰되 THP는 madvise 또는 never 두는 게 운영 표준입니다.

로컬 메모리

각 backend가 자기만 쓰는 메모리 영역. 동시 backend 수가 많을수록 이 합계가 커집니다.

파라미터기본역할메모
work_mem4MB정렬·해시 조인·해시 집계 등 1개 노드당 사용 가능 메모리한 쿼리에 정렬 노드가 여러 개면 노드 수만큼 곱해진다
hash_mem_multiplier2.0해시 작업에 한해 work_mem × multiplier까지 허용 (PG 13+)해시 spilling 방지용
temp_buffers8MB세션의 임시 테이블 페이지 캐시세션 첫 임시 테이블 사용 전에만 변경 가능
maintenance_work_mem64MBCREATE INDEX, VACUUM, ALTER TABLE 등 유지보수 작업용한 세션이 큰 값을 점유 가능. 보통 work_mem보다 크게
autovacuum_work_mem-1 (= maintenance_work_mem)autovacuum worker 1개당 메모리 상한autovacuum이 maintenance_work_mem을 다 차지하지 못하게 분리 가능
max_stack_depth2MBbackend 스택 깊이 상한커널 ulimit -s보다 1MB 작게. 재귀 SQL·PL이 깊으면 늘림

work_mem의 함정

work_mem은 “쿼리당"이 아니라 노드(operation)당 적용됩니다. 한 쿼리에 hash join 2개 + sort 1개가 있으면 최대 work_mem × 3을 한 backend가 씁니다. 거기에 동시 backend 수와 parallel worker까지 곱해지면 —

peak memory ≈ work_mem × N(operations) × N(connections) × (1 + parallel_workers)

work_mem = 64MB, max_connections = 200이고 각 쿼리에 정렬·해시 노드 3개가 있다면 이론적 최악은 64MB × 3 × 200 = 약 38GB. 운영 권장:

  • 기본은 작게(4~16MB) 잡고
  • 무거운 분석 쿼리만 세션 단위로 SET work_mem = '256MB'로 올린다
  • PG 16+의 pg_stat_io·pg_stat_statements로 spilling 빈도 추적

maintenance_work_mem 결정

autovacuum이 작아도, 큰 테이블 인덱스 빌드·VACUUM 시에는 크게 가져갈수록 빠릅니다.

시나리오추천
일반 OLTP256MB ~ 1GB
대용량 인덱스 빌드 잦음1~4GB
autovacuum이 무거운 시스템autovacuum_work_mem을 작게(256MB) 분리하고 maintenance_work_mem은 크게

effective_cache_size — 할당이 아닌 힌트

파라미터기본의미
effective_cache_size4GB옵티마이저가 가정하는 shared_buffers + OS page cache 합산 크기

이 값은 메모리를 실제로 할당하지 않는다. 단지 옵티마이저가 인덱스 스캔 vs 시퀀셜 스캔의 비용을 추정할 때 참고하는 힌트입니다. 너무 작으면 옵티마이저가 디스크 캐시가 작다고 가정해 인덱스 스캔 비용을 비싸게 봅니다.

권장값: 호스트 RAM의 50~75%.

OS 페이지 캐시 — 보이지 않는 두 번째 캐시

PostgreSQL은 디스크 I/O를 OS 표준 read()/write()로 합니다. 따라서 모든 페이지가 일단 OS page cache를 거칩니다. 같은 페이지가 shared_buffers와 OS cache에 동시에 있는 이중 캐시 구조다.

    flowchart LR
  Disk["디스크<br/>(PGDATA, pg_wal)"]
  PC["OS page cache"]
  SB["shared_buffers"]
  BE["backend"]

  Disk <--> PC
  PC <--> SB
  SB <--> BE

  classDef d fill:#fef3c7,stroke:#b45309,color:#78350f
  classDef p fill:#d1fae5,stroke:#047857,color:#064e3b
  classDef s fill:#ede9fe,stroke:#6d28d9,color:#3b0764
  classDef b fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
  class Disk d
  class PC p
  class SB s
  class BE b
  

이중 캐시의 의미:

  • shared_buffers를 너무 키우면 같은 페이지가 양쪽에 캐싱돼 메모리 낭비
  • 너무 작으면 hot page를 OS cache에서 재로딩하는 비용
  • 일반적으로 25% 권장합니다. 매우 read-heavy + 큰 buffer pool 검증된 워크로드만 40%+

Direct I/O 옵션 (io_uring, io_method)

PostgreSQL 18에서 비동기 I/O(AIO)가 본격 도입됐습니다. io_method = io_uring(Linux) 또는 worker로 설정하면 backend가 별도 worker를 통해 비동기로 페이지를 prefetch합니다. 이중 캐시 자체는 그대로지만 레이턴시가 개선됩니다.

메모리 압박 진단

증상의심 영역진단
temp_file 빈도 높음 (pg_stat_database.temp_files)work_mem 부족 — 정렬·해시가 디스크로 spill세션별 work_mem 증액
pg_stat_io에서 evicted 많음 (PG 16+)shared_buffers 부족 — hot page가 자주 밀려남shared_buffers 증액
autovacuum이 너무 느림maintenance_work_mem 부족maintenance·autovacuum_work_mem 증액
OOM Killer가 postgres 죽임work_mem × connections가 OS RAM 초과work_mem 감소 또는 max_connections 감소
옵티마이저가 인덱스 안 쓰는 경향effective_cache_size 너무 작음RAM의 50~75%로
커밋 도중 메모리 부족이 나면 클러스터가 PANIC 후 재기동할 수 있습니다. work_mem을 무리하게 올리는 대신, 작업별로 SET LOCAL로 분리하는 패턴을 권장합니다.

정리

  • 공유 메모리 = shared_buffers 외에 WAL buffer·SLRU·lock table 등. postmaster가 기동 시 한 번 할당
  • 로컬 메모리 = backend별로 work_mem·temp_buffers·플랜 캐시 등을 자체 보유
  • work_mem은 노드당 적용 — work_mem × 노드 × 연결 × parallel로 최악 케이스 추정
  • effective_cache_size는 옵티마이저 힌트, 실제 할당 아님
  • OS page cache가 두 번째 캐시 — shared_buffers를 25% 정도로 두고 OS와 분담
  • huge pages 권장, THP는 madvise/never

다음 절(1.5)에서는 이 메모리들이 실제로 가리키는 디스크 구조 — segments·pages·tuples·free space map — 봅니다.