콘텐츠로 이동

(KO) PostgreSQL 모니터링과 통계 — 섹션 개요

목차:

이 서브카테고리는 PostgreSQL의 인트로스펙션 평면이다. 백엔드가 지금 무엇을 하고 있는지 보고하고, 엔진이 무슨 일이 있었는지 누적해서 pg_stat_* 뷰와 autovacuum 스케줄러, 그리고 플래너의 “이 테이블이 재분석이 필요할 만큼 변했는가” 휴리스틱이 읽을 수 있는 숫자를 만들어 내는 기계다. 이 섹션에 속하는 코드는 거의 전부 소스 디렉터리 하나 — src/backend/utils/activity/ — 에 모여 있고, 그 물리적 경계가 곧 서브카테고리 경계다.

세 기둥이 같은 디렉터리를 공유한다. 이들을 가르는 경계는 라이브 상태 대 누적 상태다.

  • 누적 통계 시스템 (pgstat*.c) — 시간이 지나며 쌓이는 카운터들. 삽입·갱신·삭제된 튜플 수, 블록 히트·읽기 횟수, vacuum과 analyze 타임스탬프, WAL 바이트, checkpointer·bgwriter 활동량, I/O 단위 타이밍이 여기 속한다. PostgreSQL 15부터 이 기능은 공유 메모리 서브시스템이다. 이전에는 카운터 델타를 UDP 소켓으로 받아 전용 파일을 관리하던 stats-collector 보조 프로세스가 이 역할을 맡았다. 그 재설계가 이 서브카테고리가 별도 섹션으로 존재하는 이유다.
  • 대기 이벤트와 백엔드 상태 (backend_status.c, wait_event.c) — 시점별 보고. 각 백엔드는 “나는 지금 이 쿼리를 실행 중이고, 이 상태에 있으며, 현재 이벤트를 기다리고 있다”를 자신의 슬롯에 게시한다. 이 비용은 락 획득마다 갱신해도 무시할 수 있을 만큼 작다. pg_stat_activity 뒤에 있는 라이브 뷰다. 대기 이벤트 분류 체계는 wait_event_names.txt에서 코드 생성된다.
  • 진행 보고 (backend_progress.c) — 장기 실행 명령(VACUUM, CREATE INDEX, COPY, 베이스 백업 등)이 갱신하고 pg_stat_progress_* 뷰가 읽는 명령별 소규모 진행 배열. 병렬 리더·워커 집계 경로도 갖는다.

경계 — 이 섹션이 넘기는 것:

  • 숫자를 만드는 프로세스들은 다른 곳에 속한다. 종료 시 통계 파일을 직렬화하는 checkpointer, bgwriter, 재로드하는 startup 프로세스, 그리고 백엔드 생명주기server-architecture가 소유한다. 이 서브카테고리는 그 프로세스들이 내보내는 카운터를 소유하며 프로세스 자체는 소유하지 않는다.
  • 카운터가 묘사하는 기반 구조. SLRU 통계 카운터는 여기 있지만 SLRU 캐시 자체는 txn-recovery(postgres-slru.md)에 있다. IO 통계는 여기 있지만 비동기 I/O와 버퍼 기계는 storage-engine(postgres-aio.md, postgres-buffer-manager.md)에 있다.
  • 누적 시스템이 그 위에 구축된 공유 메모리·DSA 기계 — 고정 세그먼트, DSM/DSA, dshash, LWLock — 는 server-architecture(postgres-shared-memory-ipc.md)가 소유한다. 이 섹션은 통계 시스템이 그 기반을 어떻게 사용하는지를 설명하며, 기반 자체가 어떻게 동작하는지는 설명하지 않는다.
  • pg_stat_* 뷰와 SQL 함수들은 카탈로그·SQL 표면이지 별도 모듈로 분석하지 않는다. 이 섹션은 뷰가 읽는 C 보고 계층에서 멈춘다.

stats-collector → 공유 메모리 누적 통계라는 역사적 흐름은 postgres-evolution-statistics.md에 별도로 담는다. 이 라우터는 현재(REL_18) 형태를 가리키고 버전별 이야기는 그쪽에 위임한다.

두 모듈 문서는 라이브 대 누적이라는 경계를 따라 깔끔하게 나뉜다. 누적 시스템은 백엔드 로컬 대기 → 공유 저장소 → 디스크 흐름을 가진다. 대기/상태/진행 시스템은 PGPROC에 직접 게시하며 어떤 누적도 없다. 둘 다 같은 utils/activity/ 디렉터리를 사용하고, 같은 공유 메모리 기반을 server-architecture에서 빌려온다.

flowchart TB
  subgraph BACKEND["임의의 백엔드 / 보조 프로세스"]
    ACT["실행 중인 명령<br/>(쿼리, vacuum, copy, ...)"]
    PEND["대기 통계 (프로세스 로컬)<br/>PgStat_EntryRef 캐시 + have_*_stats"]
    LIVE["라이브 자기 보고<br/>MyBEEntry + MyProc 대기 슬롯"]
  end

  ACT --> PEND
  ACT --> LIVE

  subgraph CUMUL["postgres-cumulative-stats.md  (누적 뷰)"]
    FLUSH["pgstat_report_stat()<br/>트랜잭션 종료 / 타임아웃 시 플러시"]
    FIXED["고정 수량 종류<br/>단순 shmem 블록<br/>(checkpointer, bgwriter, WAL, IO, SLRU, archiver)"]
    VAR["가변 수량 종류<br/>DSA + dshash, PgStat_HashKey 키<br/>(릴레이션별, 함수별, DB별, replslot, subscription, 백엔드)"]
    FILE["디스크의 pgstat.stat<br/>(checkpointer가 종료 시 기록,<br/>startup이 재로드 / 크래시 후 버림)"]
  end

  PEND --> FLUSH
  FLUSH --> FIXED
  FLUSH --> VAR
  FIXED --> FILE
  VAR --> FILE

  subgraph LIVEDOC["postgres-wait-events-progress.md  (라이브 뷰)"]
    STATUS["백엔드 상태<br/>backend_status.c -> PgBackendStatus"]
    WAIT["대기 이벤트<br/>wait_event.c, wait_event_names.txt에서 코드 생성"]
    PROG["명령 진행<br/>backend_progress.c -> st_progress_param[]"]
  end

  LIVE --> STATUS
  LIVE --> WAIT
  LIVE --> PROG

  subgraph READERS["리더 (이 섹션 범위 밖)"]
    VIEWS["pg_stat_* / pg_stat_activity /<br/>pg_stat_progress_* 뷰"]
    AV["autovacuum 스케줄러"]
    PLAN["플래너 재분석 휴리스틱"]
  end

  FIXED --> VIEWS
  VAR --> VIEWS
  VAR --> AV
  VAR --> PLAN
  STATUS --> VIEWS
  WAIT --> VIEWS
  PROG --> VIEWS

세부 문서를 읽기 전에 이 다이어그램에서 챙겨 두어야 할 구조적 포인트가 셋 있다.

  • 누적 시스템 안의 두 저장 클래스. 고정 수량 종류(checkpointer, bgwriter, WAL, IO, SLRU, archiver처럼 대상이 하나이거나 소수인 것)는 시작 시에 확보된 단순 공유 메모리 블록에 산다. 가변 수량 종류(릴레이션별, 함수별, 데이터베이스별, 복제 슬롯, subscription, 백엔드별)는 PgStat_HashKey(종류 + dboid + objid)를 키로 삼는 dshash 해시 테이블이 놓인 동적 공유 메모리에 산다. 가변 종류의 카운터는 해시 엔트리와 별도로 할당되어(엔트리는 body를 가리키는 포인터를 가짐), 서로 다른 종류가 테이블 하나를 부피 증가 없이 공유한다.
  • 백엔드는 핫 경로에서 공유 저장소에 직접 쓰지 않는다. 백엔드는 프로세스 로컬 대기 카운터를 증가시키다가 트랜잭션 종료(또는 타임아웃) 시 pgstat_report_stat()로 플러시한다. 비용이 큰 공유 메모리 쓰기가 배치된다는 점이 PG15 재설계가 기존 UDP 패킷 수집기 방식보다 나은 핵심 이유다.
  • 라이브 보고는 훨씬 저렴하고 누적되지 않는다. 대기 이벤트와 상태 갱신은 일반 경로에서 잠금 없이 백엔드 자신의 PgBackendStatus / MyProc 슬롯에 직접 쓴다. 모든 락 대기마다 갱신해도 측정 가능한 비용이 없도록 설계한 구조다.

교차 참조 우선: 누적 시스템을 먼저 읽는다. 라이브 뷰의 상태 보고(backend_status.c)가 누적 서브시스템과 물리적으로 같은 위치에 있고 초기화도 함께 진행되기 때문이다. 고정 대 가변 종류 / DSA dshash 모델이 나머지가 쌓이는 토대이기도 하다.

  1. postgres-cumulative-stats.md — PG15 공유 메모리 서브시스템. PgStat_Kind 분류 체계, 고정·가변 저장소, 백엔드 로컬 대기 → 플러시 → dshash 경로, checkpointer/startup 파일 생명주기를 다룬다. DSA/dshash/LWLock 기반이 낯설다면 먼저 postgres-shared-memory-ipc.md(server-architecture)를 읽는다.
  2. postgres-wait-events-progress.md — 라이브 자기 보고. 백엔드 상태, 코드 생성된 대기 이벤트 분류 체계, 진행 배열을 다룬다. 내용이 가볍고 독립적이므로 두 번째로 읽기 적합하다.

이후에는 리더 쪽으로 펼쳐 읽는다. postgres-autovacuum.md와 플래너 문서들은 가변 수량 릴레이션 통계를 소비하고, postgres-evolution-statistics.md는 역사적 흐름을 담는다.

아래는 전방 참조다. 해당 모듈 문서는 아직 작성 전일 수도 있다.

모듈 문서다룰 내용
postgres-cumulative-stats.mdPG15 공유 메모리 누적 통계 시스템. PgStat_Kind 분류 체계와 PgStat_KindInfo 디스패치, 고정 수량(단순 shmem) 대 가변 수량(DSA + dshash, PgStat_HashKey 키) 저장소, 프로세스 로컬 대기 카운터 → pgstat_report_stat() 플러시 모델, 파일 생명주기(checkpointer가 종료 시 pgstat.stat 직렬화, startup이 재로드 또는 크래시 후 버림) — 즉, 기존 stats-collector 프로세스의 대체 구현.
postgres-wait-events-progress.md라이브 자기 보고 평면. PgBackendStatuspg_stat_activity 뒷받침(backend_status.c), wait_event_names.txt에서 generate-wait_event_types.pl를 거쳐 코드 생성되는 대기 이벤트 클래스 분류 체계(wait_event.c), 병렬 리더·워커 집계 포함 명령별 진행 보고(backend_progress.c).
  • server-architecture (postgres-overview-server-architecture.md) — 가장 가까운 이웃이자 가장 큰 위임처. 이 통계를 공급하고 지속하는 프로세스들(checkpointer, bgwriter, startup, 백엔드 생명주기)과 누적 시스템이 구축된 공유 메모리 / DSA / dshash / LWLock 기반을 소유한다. 이 섹션은 카운터를, 저쪽은 카운터를 내보내고 저장하는 기계를 소유한다.
  • txn-recovery (postgres-overview-txn-recovery.md) — 고정 수량 통계 종류 여럿의 주제를 공급한다. WAL 활동량, SLRU 캐시, checkpointer 작업이 여기 해당한다. SLRU와 WAL 통계 카운터는 이 섹션에 있고, SLRU 캐시와 WAL 기계 자체는 txn-recovery에 있다.
  • storage-engine (postgres-overview-storage-engine.md) — IO 통계 종류는 버퍼 매니저와 비동기 I/O 활동을 보고하고, 릴레이션 통계 종류(n_tup_ins/upd/del, n_dead_tup)는 힙 변경을 묘사한다. 그 숫자 뒤의 메커니즘(postgres-buffer-manager.md, postgres-aio.md, postgres-heap-am.md)은 storage-engine이 소유한다.
  • query-processing (postgres-overview-query-processing.md) — 소비자 측. 플래너는 캐시된 플랜과 오래된 ANALYZE 데이터 갱신 시점을 결정하기 위해 가변 수량 릴레이션 통계를 읽고, 진행 보고는 CREATE INDEX와 병렬 쿼리 진행 상황을 노출한다.