본문으로 건너뛰기

13.5 OS·HW 튜닝

PostgreSQL의 마지막 튜닝 단계는 OS와 하드웨어. 데이터베이스 파라미터를 다 만져도 OS·디스크·NUMA가 부족하면 한계가 명확. Linux 환경의 운영 권장 설정을 정리합니다.

메모리

Transparent Huge Pages — disable

THP는 PostgreSQL에 부정적이다 — 메모리 stall, CPU 사용량 폭증 사례 다수.

# 현재 상태
cat /sys/kernel/mm/transparent_hugepage/enabled
# [always] madvise never  ← always면 문제

# 비활성 (즉시)
echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled
echo never | sudo tee /sys/kernel/mm/transparent_hugepage/defrag

# 영구 (재부팅 후 유지) — /etc/rc.local 또는 systemd unit
cat << 'EOF' | sudo tee /etc/systemd/system/disable-thp.service
[Unit]
Description=Disable Transparent Huge Pages
DefaultDependencies=no
After=sysinit.target local-fs.target
Before=basic.target

[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo never > /sys/kernel/mm/transparent_hugepage/enabled'
ExecStart=/bin/sh -c 'echo never > /sys/kernel/mm/transparent_hugepage/defrag'

[Install]
WantedBy=basic.target
EOF
sudo systemctl enable disable-thp.service

정적 HugePages (PostgreSQL 권장)

shared_buffers가 큰 (수 GB+) 환경에서 정적 huge_pages 활용 — TLB miss·페이지 테이블 메모리 절약합니다.

# 2MB 페이지 1024개 = 2GB 예약
sudo sysctl -w vm.nr_hugepages=1024
# 영구
echo 'vm.nr_hugepages=1024' | sudo tee /etc/sysctl.d/40-postgresql.conf

shared_buffers 8GB → (8 × 1024) / 2 + 50 ≈ 4146개. 약간 여유 줘서 4200.

PostgreSQL:

huge_pages = try    # 가능하면 사용 (기본)
huge_pages = on     # 확보 못 하면 기동 실패

swappiness

# 메모리 부족 시 swap 사용 최소화
sudo sysctl -w vm.swappiness=10
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.d/40-postgresql.conf

기본 60은 너무 적극적. PostgreSQL이 swap에 빠지면 매우 느려집니다.

overcommit_memory

sudo sysctl -w vm.overcommit_memory=2
sudo sysctl -w vm.overcommit_ratio=80

2 = strict — overcommit 금지합니다. OOM Killer 발생 빈도 ↓. (메모리 산정 정확해야)

디스크

filesystem

파일시스템권장
ext4안정. mount option noatime,nodiratime
XFS큰 파일에 빠름. PG 권장
ZFSsnapshot 강력하지만 PG 더블 카피·복잡
btrfs일부 환경에서 CoW로 PG 성능 ↓
# /etc/fstab
/dev/nvme0n1p1  /var/lib/pgsql  ext4  noatime,nodiratime  0 2

I/O scheduler

cat /sys/block/nvme0n1/queue/scheduler
# [none] mq-deadline kyber bfq

# NVMe는 'none' 권장
echo none | sudo tee /sys/block/nvme0n1/queue/scheduler

# SATA SSD/HDD는 'mq-deadline' 또는 'kyber'

NVMe는 hardware queue가 충분해 OS scheduler가 오히려 부담입니다.

read-ahead

sudo blockdev --getra /dev/nvme0n1
# 기본 256 (= 128KB)

# 시퀀셜 read 많음 (분석)
sudo blockdev --setra 4096 /dev/nvme0n1   # 2MB

# OLTP는 기본 적당

dirty 페이지

# Linux의 dirty 페이지 한도
sudo sysctl -w vm.dirty_background_bytes=$((128*1024*1024))   # 128MB
sudo sysctl -w vm.dirty_bytes=$((512*1024*1024))               # 512MB

# 기본은 메모리 비율 (10·20%) — 너무 크면 fsync 시 폭주

큰 dirty 누적은 checkpoint sync 시간을 폭증시킵니다. byte 단위로 작게 묶음.

CPU·NUMA

NUMA

NUMA 시스템에서 PostgreSQL이 자기 NUMA 노드 메모리 우선 사용하면 좋습니다.

# NUMA 정보
numactl --hardware

# PostgreSQL을 NUMA-aware로 시작
numactl --interleave=all /usr/pgsql-17/bin/postmaster -D ...

systemd unit에 numactl --interleave=all 래핑. 큰 호스트(수십 코어)에서 효과입니다.

CPU governor

# 현재
cpupower frequency-info

# performance 모드 (전력 절약 안 함, 항상 최대)
sudo cpupower frequency-set -g performance

서버급 BIOS 설정에서도 Power Profile = Performance 권장합니다.

네트워크

sysctl

# TCP 수신·송신 버퍼
sudo sysctl -w net.core.rmem_max=16777216
sudo sysctl -w net.core.wmem_max=16777216
sudo sysctl -w net.ipv4.tcp_rmem='4096 87380 16777216'
sudo sysctl -w net.ipv4.tcp_wmem='4096 65536 16777216'

# TCP keepalive (PostgreSQL은 자체 keepalive도 있음)
sudo sysctl -w net.ipv4.tcp_keepalive_time=60
sudo sysctl -w net.ipv4.tcp_keepalive_intvl=10
sudo sysctl -w net.ipv4.tcp_keepalive_probes=6

somaxconn

sudo sysctl -w net.core.somaxconn=4096

PostgreSQL listen backlog. 동시 연결 폭주 시 새 connection 큐.

ulimit

PostgreSQL 사용자의 limit.

# /etc/security/limits.d/postgres.conf
postgres soft nofile 65536
postgres hard nofile 65536
postgres soft nproc  65536
postgres hard nproc  65536
postgres soft memlock unlimited
postgres hard memlock unlimited   # huge_pages 사용 시 필요

systemd unit에서도:

[Service]
LimitNOFILE=65536
LimitMEMLOCK=infinity

NVMe·고성능 디스크

항목권장
WAL 디스크별도 NVMe (4.5 tablespace 분리)
RAIDRAID 10 (성능+안정), RAID 5는 write penalty 큼
캐시hardware controller battery-backed cache 사용
클라우드EBS gp3 + provisioned IOPS, Azure Premium SSD v2

EBS gp3는 baseline IOPS와 burst를 잘 구분. burst balance 모니터링 필수입니다.

가상화 환경

환경추가 점검
KVMvirtio 디스크·네트워크 사용
VMwarePVSCSI 컨트롤러
AWS EC2인스턴스 family — m6i / r6i / r6id (NVMe local)
GCPn2/n2d, local SSD
AzureEbsv5, Premium SSD v2

가상화 layer의 CPU steal을 측정 (10.8). st가 5%+면 호스트 측 부하 — 도메인 이전 검토합니다.

정기 점검

# 디스크 health (NVMe)
sudo nvme smart-log /dev/nvme0n1

# SMART (SATA)
sudo smartctl -a /dev/sda

# 메모리 ECC 에러
sudo edac-util -v

# kernel 메시지
sudo dmesg -T | tail -100

월 단위 점검으로 하드웨어 사고 조기 발견.

운영 안티패턴

안티패턴영향
THP always메모리 stall, CPU 폭주
swappiness 60 (기본)PostgreSQL swap → 매우 느림
WAL과 데이터 같은 디스크commit latency 영향
ulimit 너무 작음“Too many open files”
클라우드 burst 계산 안 함사용량 폭증 시 갑작스러운 느림
가상화 CPU 부족steal time
OS·HW 튜닝은 측정 후. 변경 전 측정값이 없으면 효과 검증 불가능합니다. 시계열 메트릭(10.8) 필수입니다.

정리

  • 메모리: THP off + 정적 HugePages + swappiness 10
  • 디스크: XFS/ext4 + noatime + NVMe scheduler none + WAL 분리
  • CPU: governor performance, NUMA-aware 시작
  • 네트워크: somaxconn 4096, TCP 버퍼 16MB
  • ulimit: nofile/nproc 65536, memlock unlimited
  • 정기 디스크·메모리·dmesg 점검
  • 가상화·클라우드는 burst·steal 모니터링

다음 절(13.6)에서는 PostgreSQL 파라미터 중 가장 영향 큰 — 메모리 파라미터를 봅니다.