본문으로 건너뛰기

5.2 리소스 관리

Kubernetes는 노드의 CPU·메모리를 여러 Pod가 나눠 쓴다. 이 자원을 어떻게 요청하고 어디까지 쓸 수 있는지 명시하지 않으면, 한 Pod가 자원을 독점하거나 노드가 메모리 부족에 빠졌을 때 PostgreSQL Pod가 먼저 종료되는 일이 벌어진다. CloudNativePG는 두 가지 값으로 이를 통제한다. requests는 스케줄러가 Pod를 배치할 때 확보하는 최소 자원이고, limits는 Pod가 넘을 수 없는 상한이다.

resources:
  requests:
    memory: "32Mi"
    cpu: "50m"
  limits:
    memory: "128Mi"
    cpu: "100m"

CPU 단위 50m은 1 코어의 1000분의 50, 즉 0.05 코어를 뜻한다. 메모리 Mi는 메비바이트다. requests만 있으면 상한이 없어 다른 Pod를 압박할 수 있고, limits만 있으면 스케줄러가 자원을 미리 확보하지 못한다. 둘을 함께 쓰는 것이 기본이다.

QoS class

Kubernetes는 Pod에 지정된 requests·limits 조합에 따라 Quality of Service(QoS) class를 자동으로 매긴다. 노드가 메모리 부족(OOM)에 빠지면 이 등급이 낮은 Pod부터 축출된다.

    flowchart TD
    START[requests·limits 확인] --> Q1{requests=limits<br/>메모리·CPU 모두}
    Q1 -->|예| G[Guaranteed]
    Q1 -->|아니오| Q2{requests 또는<br/>limits 존재}
    Q2 -->|예| B[Burstable]
    Q2 -->|아니오| BE[BestEffort]
  

세 등급의 우선순위는 다음과 같다.

QoS class조건OOM 시 축출 순위
Guaranteed메모리·CPU의 requests와 limits가 서로 같음가장 나중
Burstablerequests나 limits 중 일부만 지정중간
BestEffortrequests·limits 모두 없음가장 먼저

PostgreSQL 워크로드에는 Guaranteed가 권장된다. 메모리와 CPU 각각에서 requests와 limits를 동일한 값으로 맞추면 이 등급이 된다.

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: postgresql-resources
spec:
  instances: 3
  postgresql:
    parameters:
      shared_buffers: "256MB"
  resources:
    requests:
      memory: "1024Mi"
      cpu: 1
    limits:
      memory: "1024Mi"
      cpu: 1
  storage:
    size: 1Gi
QoS가 Guaranteed일 때 CNPG는 postmaster 프로세스의 PG_OOM_ADJUST_VALUE0으로 설정한다. 그러면 OOM 상황에서 postmaster보다 자식 프로세스가 먼저 종료되므로, 인스턴스 자체는 살아남아 깨끗하게 셧다운할 여지를 남긴다.

메모리 산정과 shared_buffers

PostgreSQL의 shared_buffers는 공유 버퍼 캐시 크기다. 관례적으로 Pod 전체 메모리의 25% 안팎으로 잡는다. 위 예시처럼 메모리 limits가 1024Mi라면 shared_buffers는 256MB가 적당하다. 나머지 메모리는 work_mem·maintenance_work_mem, 그리고 운영체제 페이지 캐시가 나눠 쓴다.

정리하면 다음을 지킨다.

  • 메모리·CPU의 requests와 limits를 같은 값으로 맞춰 Guaranteed QoS를 확보한다.
  • shared_buffers는 Pod 메모리의 약 25%로 시작해 워크로드에 맞게 조정한다.
  • requests/limits를 명시해 OOMKilled와 CPU throttling을 예방한다.
  • 전용 노드가 필요하면 nodeSelector로 Pod 배치를 제한한다(5.4에서 다룬다).

hugepages

hugepages는 리눅스가 메모리를 관리하는 페이지의 크기를 기본 4KB보다 크게(예: 2MB) 잡는 기능이다. PostgreSQL처럼 큰 공유 메모리를 다루는 프로세스는 페이지 테이블 오버헤드가 줄어 성능이 좋아진다. Kubernetes에서는 hugepages도 하나의 자원이므로 resources에 명시하고, 노드에 미리 hugepages가 예약되어 있어야 한다.

spec:
  instances: 3
  postgresql:
    parameters:
      shared_buffers: "256MB"
  resources:
    requests:
      memory: "1024Mi"
      cpu: 1
      hugepages-2Mi: "512Mi"
    limits:
      memory: "1024Mi"
      cpu: 1
      hugepages-2Mi: "512Mi"
hugepages는 노드 수준에서 미리 확보되어 있어야 한다. 노드에 예약된 hugepages가 부족하면 Pod가 스케줄되지 못하고 pending 상태에 머문다. PostgreSQL의 huge_pages 파라미터를 try로 두면 hugepages 확보에 실패해도 일반 페이지로 기동을 이어 간다.

오토스케일러 연동

  • Vertical Pod Autoscaler(VPA): CNPG는 권고 전용 모드(updateMode: Off)에서만 VPA와 함께 쓴다. VPA가 제안한 값은 DBA가 직접 Cluster 매니페스트에 반영한다.
  • Horizontal Pod Autoscaler(HPA): PostgreSQL 클러스터에는 권장하지 않는다. 인스턴스를 늘려도 standby replica만 추가될 뿐 primary의 쓰기 부하는 줄지 않기 때문이다.
VPA를 Auto·Recreate·Initial 모드로 CNPG 클러스터에 붙이지 않는다. Operator는 spec.resources를 유일한 기준(source of truth)으로 삼기 때문에, VPA가 Pod 스펙에 직접 써넣은 값을 받아들이지 않는다.

다음 절에서는 데이터를 여러 볼륨에 나눠 담는 선언형 tablespace를 살펴본다.