PostgreSQL 성능 저하, 커널 7.0과 Huge Pages 문제 분석
리눅스 커널 7.0(Linux 7.0)의 PREEMPT_NONE 제거가 PostgreSQL 성능에 미치는 영향 분석
96 vCPU 환경에서 PostgreSQL의 사용자 공간 스핀락(User-space Spinlock) 병목 현상 심화 확인
Huge Pages 미사용 시 4KB 페이지 폴트(Page Fault)로 인한 성능 저하가 핵심 원인으로 지목됨
커널 커뮤니티는 rseq 도입을 제안했으나, PostgreSQL 측은 Huge Pages 설정 권장으로 대응
PREEMPT_NONE 제거와 사용자 공간 스핀락 병목
리눅스 커널 7.0에서 PREEMPT_NONE 모드가 제거되면서, 고병렬 환경(96 vCPU, 1024 클라이언트)의 PostgreSQL에서 사용자 공간 스핀락(User-space Spinlock)의 경합이 심화되었습니다. 특히 `StrategyGetBuffer` 함수 내의 `s_lock`에서 CPU 사용률의 55%가 소모되는 현상이 관찰되었는데, 이는 이전 커널 버전에서는 두드러지지 않았던 문제입니다. 커뮤니티에서는 스핀락 자체의 사용자 공간 사용을 지양해야 한다는 의견이 지배적입니다.
4KB 페이지 폴트(Page Fault)가 성능 저하의 주범
본문은 120GB 이상의 `shared_buffers`를 4KB 페이지로 매핑할 경우, 초기 접근 시 발생하는 마이너 페이지 폴트(Minor Page Fault)가 스핀락 경합 시 치명적인 성능 저하를 유발한다고 설명합니다. 스핀락 홀더가 페이지 폴트 핸들러에서 지연되는 동안, 수백 개의 다른 스레드가 사용자 공간에서 대기하며 CPU 사이클을 낭비하게 됩니다. 이는 데이터 격리 아키텍처(Data Isolation Architecture) 설정과 커널 스케줄링 정책 간의 예상치 못한 상호작용입니다.
Huge Pages 설정의 중요성 및 효과
이 문제는 Huge Pages를 사용하면 거의 사라집니다. 120GB 메모리를 2MB 또는 1GB Huge Pages로 매핑하면, 초기 페이지 폴트 수가 수천만에서 수천 또는 수백 개로 급감합니다. 또한 TLB(Translation Lookaside Buffer) 압력이 현저히 줄어들어 버퍼 관리자의 캐시 효율성이 높아집니다. 커뮤니티에서도 Huge Pages 사용이 권장 구성이며, 이를 사용하지 않는 것은 '비정상적인 구성'이라는 인식이 강합니다.
커널 커뮤니티의 제안과 PostgreSQL의 대응
리눅스 커널 개발자들은 `rseq`와 같은 메커니즘을 통해 사용자 공간이 스케줄러에게 선점 금지를 요청하는 방식을 제안했습니다. 하지만 PostgreSQL 커뮤니티는 이를 새로운 커널 기능에 대한 의존성을 강요하는 것으로 보고, `postgresql.conf`에서 `huge_pages = on` 설정을 명확히 하는 것이 현재로서는 가장 현실적인 해결책이라고 주장합니다. 이는 데이터 미저장 정책(Zero-Retention Policy)과는 별개로, 시스템 구성의 중요성을 강조하는 사례입니다.
컨테이너 환경에서의 고려사항
Kubernetes와 같은 컨테이너 환경에서는 호스트 레벨의 Huge Pages 예약 및 컨테이너에 대한 노출 설정이 필수적입니다. 이러한 설정 없이는 수십 GB 이상의 `shared_buffers`를 사용하는 PostgreSQL은 수년간 성능 문제를 겪어왔으며, 리눅스 커널 7.0 변경은 기존 문제를 더욱 악화시킬 뿐입니다. 따라서 컨테이너 런타임 및 호스트의 Huge Pages 설정이 중요하며, 불가능할 경우 `shared_buffers` 크기를 줄이거나 컨테이너 외부로 PostgreSQL을 이전하는 것을 고려해야 합니다.