AI 요약
PostgreSQL 운영 환경에서 work_mem 설정은 시스템 안정성을 결정짓는 핵심 요소이나, 동시에 관리자를 오해에 빠뜨리는 위험한 '함정'이 될 수 있습니다. 최근 2TB의 막대한 RAM을 탑재한 고사양 클러스터가 work_mem을 2MB라는 보수적인 수치로 설정했음에도 불구하고, 피크 시간대에 발생한 단일 쿼리로 인해 OOM 킬러가 작동하여 전체 시스템이 중단되는 사고가 발생했습니다. 전문가 Henrietta Dombrovskaya와 저자는 Postgres 14에서 도입된 pg_log_backend_memory_contexts 함수를 활용하여 문제의 백엔드 메모리 구조를 정밀 분석했습니다. 분석 결과 단일 백엔드에서 약 557MB 이상의 메모리가 사용되었으며, 특히 ExecutorState에서 52만 개가 넘는 메모리 청크(chunk)가 생성된 것이 확인되었습니다. 이는 work_mem이 쿼리 단위가 아니라 각 해시/정렬 연산 및 병렬 워커마다 개별적으로 할당되기 때문에 발생하는 현상으로, 복잡한 쿼리에서는 설정값의 수백 배에 달하는 메모리가 점유될 수 있음을 시사합니다.
핵심 인사이트
- 2TB RAM의 무력화: 고사양 하드웨어임에도 불구하고
work_mem의 동작 방식에 대한 오해로 인해 단일 쿼리가 전체 메모리를 점유하여 OOM 킬러를 유발했습니다. - 연산 단위 할당:
work_mem은 쿼리당 제한이 아니라, 쿼리 내부의 각 해시(Hash) 및 정렬(Sort) 작업마다 독립적으로 적용되는 수치입니다. - 진단 도구의 활용: PostgreSQL 14 버전부터 도입된
pg_log_backend_memory_contexts(PID)함수가 특정 백엔드의 메모리 할당 트리를 로그로 덤프하여 문제의 원인을 밝히는 결정적 역할을 했습니다. - 폭발적인 청크 생성: 재현 테스트 결과 ExecutorState에서만 524,059개의 메모리 청크가 생성되는 등 비정상적으로 파편화된 메모리 사용 패턴이 관찰되었습니다.
주요 디테일
- 로그 분석 수치: 단일 백엔드 재현 사례에서 ExecutorState는 약 235MB(40개 블록), HashTableContext는 약 340MB(47개 블록)를 사용하고 있었습니다.
- 전체 메모리 점유: 재현 서버의 단일 백엔드 총 메모리 사용량은 586,713,672 바이트(약 557MB)에 달했으며, 운영 서버에서는 이 규모가 2TB를 초과했습니다.
- 병렬 워커의 영향: 쿼리에 병렬 워커가 동원될 경우 각 워커가 독립적인
work_mem한도를 가지게 되어 메모리 사용량이 기하급수적으로 늘어납니다. - 사건의 맥락: 2026년 3월 11일 게시된 이 사례는 Henrietta Dombrovskaya가 Telegram을 통해 저자에게 운영 클러스터 중단 사실을 알리며 조사가 시작되었습니다.
- 운영 vs 재현: 운영 클러스터는 OOM으로 즉시 중단되었으나, 조사 과정에서는 별도 서버에서 쿼리를 실행한 뒤 OOM이 발생하기 전 중단시켜 상세 로그를 확보했습니다.
향후 전망
- 설정 가이드의 재정립: DB 관리자들은
work_mem설정 시 병렬 쿼리 빈도와 쿼리 복잡성을 고려하여 더욱 정밀한 할당 전략을 수립해야 할 것입니다. - 모니터링 강화: Postgres 14 이상의 환경에서 실시간 메모리 컨텍스트 로깅을 통한 사전 장애 감지 기법이 널리 공유될 것으로 보입니다.
