콘텐츠로 이동

(KO) PostgreSQL 아키텍처 개요 — 단일 바이너리, 공유 메모리 머신, WAL 척추

목차

이 문서는 PostgreSQL 코드 분석 트리의 정문이다. PostgreSQL 소스를 한 줄도 읽지 않은 독자가 큰 그림부터 잡고 들어오라고 만들었다. 어떤 프로세스들이 돌고, 무엇을 공유하며, 질의 하나가 엔진 안에서 어떻게 이동하고, 내구성과 동시성을 무엇이 보장하는지를 먼저 파악한 뒤 약 95개의 세부 문서 가운데 어느 것을 펼칠지 결정하는 용도로 쓴다. 절마다 일부러 얕게 적었다. 경계를 짚고 해당 메커니즘을 소유한 세부 문서를 가리키는 것이 이 문서의 역할이다. 절이 얇아 보이는 것은 의도된 깊이다.

두 번째 독자는 세부 문서 몇 편을 이미 읽었고 그것들을 한 줄기로 엮고 싶은 엔지니어다. “SELECT 하나가 와이어에서 heap 페이지까지 어떻게 다녀오는가”, “스냅샷이 실제로 무엇을 읽는가”, “더티 버퍼를 flush하려면 왜 WAL을 기다려야 하는가” 같은 질문은 여러 서브시스템의 경계를 동시에 넘는다. 이 문서의 다이어그램은 그 경계에 이름을 붙여 두므로, 함께 읽어야 할 세부 문서의 짝을 고를 때 도움이 된다.

세 번째 독자는 PostgreSQL이 지금 같은 모양인지 궁금한 사람이다. 정의적 설계 선택들 — 스레드나 별도 데몬 대신 단일 fork 바이너리, 부팅 시 한 번만 크기를 정하는 고정 공유 메모리 세그먼트, vacuum이 필요한 no-overwrite MVCC 힙, 모든 것의 보편적 이벤트 로그인 WAL, 플러그인 접근 방법/리소스 매니저/훅/FDW/백그라운드 워커로 구성된 확장성 표면 — 은 버클리 POSTGRES 프로젝트에서 출발한 OODB·학술 계보의 의도적 트레이드오프다. 세부 문서들이 각각 깊이 다루고, postgres-design-philosophy.md(계획됨)가 근거를 모은다.

버전 주석. 이 트리는 REL_18_STABLE(커밋 273fe94, PostgreSQL 18.x) 클론 소스를 기준으로 작성됐다. 심볼 이름이 기준점이며, 세부 문서의 “소스 검증” 절에서 이 커밋의 줄 번호를 고정한다.

핵심 명제: 프로세스 트리가 아니라 공유 메모리 머신

섹션 제목: “핵심 명제: 프로세스 트리가 아니라 공유 메모리 머신”

다른 DBMS 내부를 읽어 본 적 있다면 한 가지 가정을 입구에 내려 두어야 한다. PostgreSQL에서 프로세스는 아키텍처가 아니다. 아키텍처는 프로세스들이 조율하는 공유 메모리이고, 프로세스는 그 머신의 교체 가능한 주민이다.

구체적으로 세 가지를 짚어 두면 된다.

  • PostgreSQL은 단일 실행 파일이다. 별도의 서버/브로커/에이전트 바이너리가 없다. 하나의 postmaster 프로세스가 모든 다른 프로세스를 자신으로부터 fork()한다(launch_backend.cpostmaster_child_launchfork_process). fork()가 없는 Windows에서는 자식이 같은 바이너리를 재실행해 재연결하는 EXEC_BACKEND 경로를 쓰지만, 이는 이식성 대안이지 별도 아키텍처가 아니다.
  • 모든 자식 프로세스는 postmaster 시작 시점에 한 번만 크기가 계산되어 생성된 하나의 공유 메모리 세그먼트에 연결된다. 크기 계산은 CalculateShmemSize, 생성은 CreateSharedMemoryAndSemaphores(ipci.c)가 담당한다. 세그먼트는 요구에 따라 늘어나지 않는다. 공유 메모리가 필요한 확장 기능은 세그먼트 크기가 정해지기 전에 shmem_request_hook / RequestAddinShmemSpace 경로로 미리 예약해야 한다.
  • 상태는 세그먼트 안에 있다. 프로세스 안에 있지 않다. 백엔드별 PGPROC 슬롯과 전역 ProcGlobal(proc.h), 모든 스냅샷의 뒷받침이 되는 procarray(procarray.c), 공유 버퍼 풀, 헤비웨이트 락 테이블, 서술 락(SSI) 구조체, 공유 무효화 큐가 모두 여기 산다. 백엔드는 LWLock 보호 아래 공유 상태를 조작하는 제어 흐름에 불과하며, 개인 메모리 컨텍스트 트리는 그 작업을 위한 작업대다.

그림 1 — 하나의 공유 메모리 세그먼트와 역할별 프로세스들

이 그림을 제대로 잡아 두면 나머지 트리는 자연스럽게 따라온다. 버퍼 매니저, 락 매니저, procarray, WAL 삽입 경로는 모두 “나는 공유 구조체를 건드리는 많은 프로세스 중 하나다, 래치 아래”라는 전제 위에서 동작한다. 아래 일곱 축은 같은 머신을 서로 다른 각도에서 바라본 것이다.

PostgreSQL의 프로세스 역할은 바이너리 집합이 아니라 열거형(enum)이다. miscadmin.hBackendType 이 postmaster가 fork할 수 있는 모든 프로세스 종류를 열거한다. 새로운 종류를 추가하려면 launch_backend.cchild_process_kinds 배열에도 등록해야 한다.

// BackendType — src/include/miscadmin.h
typedef enum BackendType
{
B_INVALID = 0,
B_BACKEND, // a client session
B_DEAD_END_BACKEND,
B_AUTOVAC_LAUNCHER, B_AUTOVAC_WORKER,
B_BG_WORKER, // extension / parallel / logical-apply workers
B_WAL_SENDER, B_SLOTSYNC_WORKER,
B_STANDALONE_BACKEND, // single-user mode (initdb, --single)
/* auxiliary procs: one of each (except IO workers) */
B_ARCHIVER, B_BG_WRITER, B_CHECKPOINTER, B_IO_WORKER,
B_STARTUP, B_WAL_RECEIVER, B_WAL_SUMMARIZER, B_WAL_WRITER,
B_LOGGER, // NOT attached to shared memory
} BackendType;

이 열거형에서 읽어야 할 세 가지가 있다.

  1. 클라이언트 세션은 B_BACKEND다. 연결 하나당 fork된 백엔드 하나가 대응한다. 커넥션 풀링은 엔진 외부(PgBouncer / pgpool)에 맡긴다. 백엔드는 자기 세션의 파싱→플래닝→실행 파이프라인 전체(축 5)를 직접 수행한다.
  2. 보조 프로세스들이 엔진의 배경 기계다. B_STARTUP은 크래시/아카이브 복구(축 3)를, B_CHECKPOINTER·B_BG_WRITER·B_WAL_WRITER는 더티 버퍼와 WAL을 디스크로 밀어낸다. B_AUTOVAC_LAUNCHER는 no-overwrite 힙에 대한 B_AUTOVAC_WORKER를 스케줄하고, B_WAL_SENDER/B_WAL_RECEIVER는 복제를 담당한다. 최근에 추가된 역할들 — PG18 비동기 I/O 서브시스템용 B_IO_WORKER, 페일오버 슬롯용 B_SLOTSYNC_WORKER — 은 엔진이 같은 fork-and-attach 모델에 계속 역할을 추가하고 있음을 보여 준다.
  3. B_LOGGER는 규칙을 증명하는 예외다. 이 프로세스는 명시적으로 공유 메모리에 연결되지 않고 PGPROC도 없다. 파이프로 들어오는 로그 메시지를 받아내기만 한다. 그 외 모든 것은 공유 메모리 머신 안에 산다.

세부 문서: postgres-postmaster.md(fork 모델과 자식 레지스트리), postgres-backend-lifecycle.md(B_BACKENDInitPostgres부터 메시지 루프까지 하는 일), postgres-aux-processes.md(checkpointer, bgwriter, walwriter, startup, syslogger), postgres-background-workers.md(B_BG_WORKER 프레임워크), postgres-autovacuum.md.

이 축이 척추다. CUBRID 분석에는 대응하는 축이 없다. CUBRID의 프로세스들은 상태를 각자 소유하고 소켓으로 주고받는 반면, PostgreSQL의 프로세스들은 하나의 세그먼트 안에서 상태를 공유하고 락과 시그널로 접근을 조율한다. 나머지 여섯 축에 등장하는 모든 것은 결국 여기 있는 구조체를 읽거나 쓴다.

flowchart TB
  subgraph BOOT["postmaster 시작 시 (한 번)"]
    CALC["CalculateShmemSize()<br/>모든 서브시스템의 요청을 합산"]
    CREATE["CreateSharedMemoryAndSemaphores()<br/>고정 세그먼트를 매핑"]
    HOOK["shmem_request_hook / shmem_startup_hook<br/>(확장 기능이 여기서 예약)"]
  end
  CALC --> CREATE
  HOOK --> CALC

  subgraph SEG["공유 세그먼트"]
    PGPROC["PGPROC[] + ProcGlobal<br/>프로세스별 슬롯, 대기 큐"]
    PROCARR["procarray<br/>실행 중 XID → 스냅샷"]
    BUFPOOL["버퍼 풀<br/>(BufferDesc[] + 블록)"]
    LOCKTBL["락 테이블 (LOCK/PROCLOCK 해시)"]
    PREDLOCK["서술 락 (SSI)"]
    SINVAL["sinval 메시지 큐"]
    DSMREG["dsm / dsa 레지스트리<br/>(동적 + 병렬 세그먼트)"]
  end
  CREATE --> SEG

  subgraph COORD["조율 프리미티브"]
    LWLOCK["LWLock<br/>(단기, 공유 구조체 보호)"]
    SPIN["스핀락 / 원자 연산"]
    HWLOCK["헤비웨이트 락<br/>(SQL 가시적, 교착 감지)"]
    LATCH["래치 / 시그널<br/>(procsignal, SetLatch)"]
  end
  SEG --- COORD

아키텍처를 이해할 때 자주 혼동되는 두 가지 구분을 짚어 두면 도움이 된다.

  • 정적 vs 동적 공유 메모리. 메인 세그먼트는 부팅 시에 고정된다. 그러나 병렬 질의와 일부 확장 기능은 부팅 이후에도 별도 공유 메모리를 요구한다. 그래서 PostgreSQL은 DSM(동적 공유 메모리 세그먼트), DSA(그 위의 동적 할당자), shm_mq(병렬 워커 튜플 스트림용 단일 리더/라이터 메시지 큐)를 추가한다. postgres-shared-memory-ipc.md 참조.
  • LWLock vs 헤비웨이트 락. LWLock은 메모리 안의 공유 구조체(버퍼 헤더, 해시 파티션)를 보호하는 단기 두 모드(공유/배타) 래치다. 교착 감지가 없고 SQL에 보이지 않는다. 헤비웨이트 락은 릴레이션·튜플·트랜잭션에 대한 SQL 수준 락 테이블(AccessShareLock ~ AccessExclusiveLock)이며 완전한 waits-for 교착 감지기를 갖는다. 둘은 별개의 서브시스템이다. postgres-lwlock-spinlock.mdpostgres-lock-manager.md가 각각 담당한다. 스냅샷 격리(SERIALIZABLE) 충돌은 세 번째 메커니즘인 서술 락이고, postgres-ssi-predicate-locking.md가 다룬다.

세부 문서: postgres-shared-memory-ipc.md, postgres-procarray.md, postgres-lwlock-spinlock.md, postgres-lock-manager.md, postgres-ssi-predicate-locking.md, postgres-latch-signals.md, postgres-cache-invalidation.md(sinval 루프).

Write-Ahead Log(선행 기록 로그, WAL)는 PostgreSQL의 단일 내구성 이벤트 로그다. 거의 모든 내구성·분산 기능은 이 로그의 소비자다. ARIES 계열 엔진에서 이 축은 곧바로 이식된다. 쓰기 전에 로그하고, 복구 시 앞으로 재생한다. PostgreSQL에서 WAL이 척추인 이유는 얼마나 많은 서브시스템이 같은 스트림을 읽는가에 있다.

flowchart LR
  subgraph PRODUCE["WAL 생성"]
    INS["XLogInsert()<br/>rmgr별 레코드"]
    RMGR["리소스 매니저<br/>(Heap, Btree, Xact, CLOG, ...)"]
    BUFW["버퍼 매니저<br/>(flush 전 WAL: 규칙)"]
  end
  RMGR --> INS
  BUFW -- "LSN 게이트" --> INS
  INS --> WALFILES["WAL 세그먼트<br/>(pg_wal/)"]

  subgraph CONSUME["WAL 소비자"]
    REDO["startup 프로세스<br/>크래시 / 아카이브 복구 (redo)"]
    PHYS["walsender → walreceiver<br/>물리 스트리밍 복제"]
    LOGIC["논리 디코딩<br/>reorderbuffer → pgoutput"]
    ARCH["archiver + wal summarizer<br/>(PITR, 증분 백업)"]
    BASE["basebackup / pg_rewind"]
  end
  WALFILES --> REDO
  WALFILES --> PHYS
  WALFILES --> LOGIC
  WALFILES --> ARCH
  WALFILES --> BASE

리소스 매니저(rmgr) 테이블(rmgrlist.h)이 WAL을 확장 가능하고 자기 서술적으로 만드는 장치다. 레코드 하나마다 rmgr id가 붙고, rmgr은 redo, desc, identify, 선택적 마스킹, 그리고 논리 복제에 결정적인 decode 콜백을 제공한다. 내장 집합은 XLOG, Transaction, Storage, CLOG, MultiXact, Heap/Heap2, Btree, Hash, Gin, Gist, SPGist, BRIN, Sequence, CommitTs, ReplicationOrigin, Generic, LogicalMessage, Database, Tablespace, RelMap, Standby 등을 포함한다. 확장 기능은 RegisterCustomRmgr(축 7)로 등록할 수 있다.

// rmgr table entry — src/include/access/rmgrlist.h
// PG_RMGR(id, name, redo, desc, identify, startup, cleanup, mask, decode)
PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, heap_identify,
NULL, NULL, heap_mask, heap_decode)
PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, btree_identify,
btree_xlog_startup, btree_xlog_cleanup, btree_mask, NULL)

WAL-before-flush 규칙이 이 축과 축 4 사이의 접합부다. 버퍼 매니저는 해당 변경을 기술하는 WAL 레코드가 내구적이 되기 전에 더티 페이지를 디스크에 쓸 수 없다. 페이지의 LSN(로그 시퀀스 번호)이 flush를 막는 게이트다. SELECT가 로그에서 블록되지 않고 COMMIT이 블록되는 이유, checkpointer와 walwriter가 존재하는 이유가 바로 이 규칙 하나에서 나온다.

세부 문서: postgres-xlog-wal.md, postgres-wal-records-rmgr.md, postgres-recovery-redo.md, postgres-checkpoint.md, postgres-xact.md, postgres-two-phase-commit.md, postgres-clog-commit-ts.md, postgres-slru.md. MVCC 가시성(postgres-mvcc-snapshots.md)은 이 축이 기록하는 커밋 상태를 읽고, vacuum(postgres-vacuum.md)은 MVCC가 남긴 것을 회수한다.

축 4 — 스토리지와 플러그인 접근 방법

섹션 제목: “축 4 — 스토리지와 플러그인 접근 방법”

실행기 아래, PostgreSQL은 OS 파일에서 페이지 위 튜플까지 엄격한 계층 구조를 이룬다. CUBRID에는 없는 핵심 비틀림이 하나 있다. 접근 방법(access method)이 플러그인이라는 점이다. 테이블은 TableAmRoutine으로, 인덱스는 IndexAmRoutine으로 간접 호출된다. heap은 기본 테이블 AM일 뿐이다.

그림 2 — 익스큐터부터 데이터 파일까지, 스토리지와 플러거블 액세스 메서드

// the table AM indirection — src/include/access/tableam.h
typedef struct TableAmRoutine
{
NodeTag type;
TableScanDesc (*scan_begin) (Relation rel, ...);
// tuple_insert / tuple_update / tuple_delete / index_fetch_tuple ...
} TableAmRoutine;

독자가 앞으로 계속 가지고 다녀야 할 구조적 핵심이 세 가지 있다.

  • 힙은 no-overwrite(MVCC)다. UPDATE는 새 튜플 버전을 쓰고 이전 버전을 스냅샷 독자용으로 남긴다. 삭제도 논리적으로만 표시된다. 그 결과로 vacuum가시성 맵이 엔진에 붙는다. in-place 엔진과의 가장 깊은 설계 차이다. postgres-heap-am.md가 담당한다(HOT에 대해서는 README.HOT 함께).
  • 버퍼 매니저가 메모리와 디스크 사이의 병목 지점이다. WAL-before-flush 규칙(축 3)이 flush 경로에 산다. postgres-buffer-manager.md.
  • smgr이 릴레이션을 파일 세그먼트(1GB 단위)로 매핑한다. 슬롯 페이지 레이아웃(ItemId 라인 포인터)은 모든 AM이 공유한다. postgres-smgr-md.md, postgres-page-layout.md.

세부 문서: postgres-table-am.md, postgres-heap-am.md, postgres-index-am.md, postgres-nbtree.md, postgres-gin.md, postgres-gist.md, postgres-spgist.md, postgres-brin.md, postgres-hash-index.md, postgres-buffer-manager.md, postgres-smgr-md.md, postgres-page-layout.md, postgres-toast.md, postgres-visibility-map.md, postgres-free-space-map.md, postgres-aio.md(PG18 비동기 I/O).

질의는 교과서적인 파이프라인을 따라 흐른다. 단계별 진입점은 tcop/postgres.c에 있고, 이것이 읽기 경로의 척추를 이룬다.

flowchart LR
  SQL["SQL 텍스트"] --> PARSE["pg_parse_query<br/>(gram.y / scan.l)<br/>원시 파스 트리"]
  PARSE --> ANALYZE["파스 분석<br/>(parse_analyze)<br/>Query 트리"]
  ANALYZE --> REWRITE["pg_analyze_and_rewrite<br/>(규칙 시스템, 뷰, RLS)"]
  REWRITE --> PLAN["pg_plan_queries<br/>(플래너: 경로 → Plan)"]
  PLAN --> PORTAL["PortalStart / PortalRun<br/>(실행기)"]
  PORTAL --> EXEC["ExecutorRun<br/>노드 트리 pull 모델"]
  EXEC --> AM["테이블 / 인덱스 AM (축 4)"]

독자가 붙들고 있어야 할 핵심이 네 가지 있다.

  • 플랜 생성의 두 문법. 플래너는 후보 Path(비용 모델로 최소 비용 우선)를 쌓은 뒤, 승리한 경로를 실행 가능한 Plan 트리로 변환한다. 조인 순서 결정에는 동적 프로그래밍을, 임계값을 넘으면 유전 알고리즘(GEQO)을 폴백으로 쓴다. postgres-planner-overview.md, postgres-path-generation.md, postgres-join-ordering.md, postgres-cost-model.md, postgres-plan-creation.md.
  • 실행기는 demand-pull 트리다. 플랜 노드마다 ExecProcNode를 호출하는 pull 구조이며, 표현식 평가는 switch-threaded 인터프리터로 컴파일된다(JIT 옵션 가능). postgres-executor.md, postgres-expression-eval.md, 노드별 문서(postgres-scan-nodes.md, postgres-join-nodes.md, postgres-agg-sort-nodes.md), postgres-jit.md.
  • 병렬성은 같은 트리의 fork다. Gather 노드가 서브플랜 사본을 실행하는 백그라운드 워커를 띄우고, 튜플은 shm_mq(축 2)로 스트리밍된다. postgres-parallel-query.md.
  • prepared statement와 포털이 실행 간 플랜을 캐시한다. postgres-portals-prepared.md.

세부 문서: postgres-parser.md, postgres-analyze-transform.md, postgres-rewriter.md, postgres-node-trees.md, postgres-extended-statistics.md, postgres-tuplesort.md.

PostgreSQL은 카탈로그 주도 엔진으로 유명하다. 타입, 연산자, 함수, 접근 방법, 인덱스 전략이 모두 pg_* 시스템 테이블의 행이다. 이것이 런타임 확장성의 근거다. 모든 백엔드가 카탈로그를 상시 읽기 때문에, 세 단계의 캐시가 그 앞에 배치되고, 공유 무효화 루프가 프로세스 간 정합성을 유지한다.

flowchart TB
  CAT["시스템 카탈로그<br/>pg_class, pg_attribute, pg_proc,<br/>pg_type, pg_am, pg_index, ..."]
  CAT --> RELCACHE["relcache<br/>(릴레이션 디스크립터)"]
  CAT --> CATCACHE["catcache / syscache<br/>(튜플 조회)"]
  RELCACHE --> BACKEND["백엔드가 캐시된<br/>메타데이터로 실행"]
  CATCACHE --> BACKEND
  DDL["DDL 커밋<br/>(축 7 ProcessUtility)"] --> INVAL["CacheInvalidate*"]
  INVAL --> SINV["sinval 큐 (공유 메모리, 축 2)"]
  SINV -. "모든 백엔드가 드레인 + 무효화" .-> RELCACHE
  SINV -.-> CATCACHE

기억해야 할 접합부가 하나 있다. 한 백엔드의 DDL이나 카탈로그 변경은 다른 백엔드의 캐시를 직접 건드리지 않는다. 공유 무효화 메시지를 큐에 넣고, 각 백엔드는 정해진 체크 포인트에서 큐를 드레인해 낡은 캐시 항목을 버린다. 이 sinval 루프가 축 6을 축 2의 공유 메모리 기반으로 다시 묶는다.

세부 문서: postgres-system-catalogs.md, postgres-relcache.md, postgres-catcache-syscache.md, postgres-cache-invalidation.md, postgres-dependency-tracking.md, postgres-namespace-search-path.md.

이 축은 CUBRID 트리에 대응물이 없다. 그러면서도 PostgreSQL 코드베이스가 지금 같은 모양인 이유 자체다. 확장성은 부가 기능이 아니다. 서드파티 코드가 엔진을 패치하지 않고도 꽂히는 간접 지점(indirection point)들 위에 코어가 세워져 있다.

flowchart TB
  CORE["PostgreSQL 코어"]
  CORE --> TAMX["테이블 / 인덱스 AM<br/>(TableAmRoutine, IndexAmRoutine — 축 4)"]
  CORE --> RMGRX["커스텀 WAL 리소스 매니저<br/>(RegisterCustomRmgr — 축 3)"]
  CORE --> HOOKX["훅 전역 변수<br/>(planner_hook, ExecutorStart_hook,<br/>ProcessUtility_hook, shmem_*_hook)"]
  CORE --> FDWX["외부 데이터 래퍼<br/>(FdwRoutine)"]
  CORE --> BGWX["백그라운드 워커<br/>(RegisterBackgroundWorker — 축 1/2)"]
  CORE --> PLX["절차형 언어 + SPI<br/>(PL/pgSQL 핸들러, SPI_*)"]
  CORE --> CSX["커스텀 스캔 제공자<br/>(CustomScanMethods)"]
  CORE --> EXTX["확장 기능<br/>(CREATE EXTENSION 패키징)"]

각 플러그 포인트는 콜백 구조체이거나 코어가 정해진 자리에서 확인하는 함수 포인터 전역 변수다. 확장 기능은 공유 라이브러리를 올리고, 구조체를 채우고, 등록한다. contrib/postgres_fdw(FDW), pg_stat_statements(planner_hook + 공유 메모리), 트리 내 인덱스 AM들이 모두 같은 패턴의 사례다. “X가 코어인가 contrib인가”가 반복되는 범위 질문인 이유도 여기 있다(postgres-coverage.md 참조). 메커니즘은 코어에 있고, 많은 구현이 contrib 또는 서드파티로 배포된다.

세부 문서: postgres-fdw.md, postgres-extensions.md, postgres-hooks.md, postgres-custom-scan.md, postgres-plpgsql.md, postgres-spi.md. AM, rmgr, bgworker에 대해서는 축 1/2/3/4 세부 문서 참조.

깊이 파고들 때 권장하는 상호 참조 순서다.

  1. 머신 — 이 개요, 이어서 postgres-shared-memory-ipc.md, postgres-postmaster.md, postgres-backend-lifecycle.md. 다른 무엇보다 fork-and-attach 모델을 먼저 이해한다.
  2. 스토리지 바닥postgres-page-layout.md, postgres-buffer-manager.md, postgres-table-am.md, postgres-heap-am.md, postgres-nbtree.md.
  3. 내구성 척추postgres-xlog-wal.md, postgres-xact.md, postgres-mvcc-snapshots.md(+ postgres-procarray.md), postgres-recovery-redo.md, postgres-vacuum.md.
  4. 동시성postgres-lock-manager.md, postgres-lwlock-spinlock.md, postgres-ssi-predicate-locking.md.
  5. 질의 경로postgres-parser.md, postgres-planner-overview.md, postgres-executor.md.
  6. 카탈로그postgres-system-catalogs.md, postgres-relcache.md, postgres-catcache-syscache.md.
  7. 이후 관심에 따라 복제, DDL, 확장성, 모니터링, 국제화/텍스트, postgres-evolution-*.md 아크로 뻗어 나간다.

세부 문서들은 열세 개의 서브카테고리로 묶이며, 각각 해당 서브카테고리의 섹션 개요 라우터(postgres-overview-<subcat>.md)를 가진다. 서브카테고리와 PostgreSQL 소스 트리 간 매핑, 그리고 모듈별 작업 목록은 postgres-coverage.md에 있다.

서브카테고리다루는 내용섹션 개요
storage-engine페이지, 버퍼, smgr, 테이블/인덱스 AM, TOAST, FSM/VM, 체크섬postgres-overview-storage-engine.md
txn-recoveryMVCC + 스냅샷 + procarray, WAL, clog/SLRU, 2PC, 복구, vacuum, 체크포인트postgres-overview-txn-recovery.md
query-processing파싱 → 분석 → 재작성 → 플래닝 → 실행, 통계, JIT, 병렬postgres-overview-query-processing.md
server-architecturepostmaster, 백엔드 수명 주기, IPC, 락(LW + 헤비 + SSI), 보조 프로세스postgres-overview-server-architecture.md
monitoring-stats누적 통계, 대기 이벤트, 진행 보고postgres-overview-monitoring-stats.md
system-catalog카탈로그 레이아웃, relcache/catcache, 무효화, 의존성, 네임스페이스postgres-overview-system-catalog.md
ddl-schemaDDL 실행, ALTER, 파티셔닝, 제약, 트리거, COPY, RLSpostgres-overview-ddl-schema.md
replication-ha물리/논리 복제, 슬롯, 아카이빙, 백업, 증분postgres-overview-replication-ha.md
client-protocolFE/BE 와이어 프로토콜, 인증, TLS/GSSAPIpostgres-overview-client-protocol.md
extensibilityFDW, 확장 기능, 훅, 커스텀 스캔, PL/pgSQL, SPIpostgres-overview-extensibility.md
base-infra메모리 컨텍스트, elog, fmgr, 데이터 타입, GUC, 정렬, dynahashpostgres-overview-base-infra.md
i18n-text전문 검색, 정렬 제공자, 인코딩postgres-overview-i18n-text.md
utilitiesinitdb/genbki, pg_dump, pg_upgrade, basebackup, combinebackup, waldump, psqlpostgres-overview-utilities.md

횡단적 역사 아크는 postgres-evolution-*.md 문서들에 별도로 담긴다(복제, vacuum/가시성, 파티셔닝, 병렬 질의, 통계, 플러그인 스토리지, 비동기 I/O).