리눅스 메모리 스와피니스와 캐시 동작 튜닝 모범 사례
워크로드 예제, sysctl 명령어, 검증 단계를 포함하여 리눅스 스와피니스와 VFS 캐시 동작을 신중하게 튜닝합니다.
리눅스 메모리 스와피니스와 캐시 동작 튜닝 모범 사례
리눅스는 사용 가능한 RAM을 사용합니다. free -h에서 서버에 "사용 가능" 메모리가 거의 없는 것을 처음 보면 놀랄 수 있습니다. 대부분의 메모리는 페이지 캐시, 디렉터리 항목(dentry), inode 캐시일 수 있으며, 메모리 누수가 아닙니다. 어려운 점은 커널이 RAM을 효율적으로 사용하고 있는지, 아니면 메모리 회수(reclaim)가 애플리케이션에 영향을 미치기 시작하는지 아는 것입니다.
리눅스 메모리 튜닝에서 자주 언급되는 두 가지 sysctl 설정은 vm.swappiness와 vm.vfs_cache_pressure입니다. 이들은 유용하지만, 마법 같은 성능 스위치는 아닙니다. 잘못된 값은 실제 문제를 숨기거나 한 워크로드의 문제를 다른 워크로드로 전가할 수 있습니다.
리눅스 메모리 관리 매개변수 이해하기
리눅스는 시스템에 더 많은 여유 RAM이 필요할 때 회수할 메모리 페이지를 결정하기 위해 휴리스틱을 사용합니다. 커널 매개변수로 제어되는 두 가지 주요 영역은 스와핑(비활성 메모리 페이지를 디스크로 이동)과 캐싱(파일 시스템 메타데이터와 데이터를 RAM에 유지)입니다.
1. vm.swappiness
vm.swappiness는 커널이 프로세스를 물리적 메모리에서 디스크의 스왑 공간으로 이동시키는 경향을 결정합니다. 0에서 100 사이의 값입니다.
- 높은 값(예: 일반적인 기본값인 60): 커널이 익명 메모리를 회수하고 스왑을 일반 메모리 관리의 일부로 사용할 가능성이 더 높습니다. 이는 페이지 캐시를 보존할 수 있지만, 활성 페이지가 밀려나면 지연 시간에 민감한 서비스에 해를 끼칠 수 있습니다.
- 낮은 값(예: 10 이하): 커널은 프로세스를 스왑아웃하기 전에 페이지 캐시에서 메모리를 회수하는 것을 선호합니다. 이렇게 하면 실행 중인 애플리케이션이 RAM에 더 오래 유지되어 응답성이 향상되지만, 시스템이 지속적으로 캐시 페이지를 삭제해야 하는 경우 디스크 I/O 성능이 저하될 수 있습니다.
- 값 0: 커널은 가능한 한 스와핑을 피하지만, 이것이 스왑을 비활성화하지는 않습니다. 스왑을 비활성화해야 하는 경우
swapoff를 사용하고 먼저 OOM(Out-Of-Memory) 위험을 이해하십시오.
vm.swappiness의 실제 적용
최적 설정은 워크로드에 따라 크게 달라집니다:
| 워크로드 유형 | 권장 swappiness 범위 |
근거 |
|---|---|---|
| 데이터베이스 서버, 고성능 컴퓨팅(HPC) | 1 - 10 | 스왑 지연 시간이 캐시 삭제보다 더 나쁠 때 좋은 시작점인 경우가 많습니다. 실제 워크로드 메트릭으로 검증하십시오. |
| 범용 서버, 데스크톱 | 30 - 60 | 스왑 동작이 문제를 일으킨다는 증거가 없는 한 일반적으로 합리적입니다. |
| 파일 서빙 또는 캐시 중점 시스템 | 경우에 따라 60 이상 | 페이지 캐시를 보존할 수 있지만, 워크로드에 대해 가끔 스와핑이 허용되는 경우에만 의미가 있습니다. |
현재 값 확인 방법:
cat /proc/sys/vm/swappiness
임시로 값 변경 방법(재부팅 전까지):
swappiness를 10으로 설정하려면:
sudo sysctl vm.swappiness=10
영구적으로 값 변경 방법:
/etc/sysctl.conf 파일을 편집하고 다음 줄을 추가하거나 수정하십시오:
# /etc/sysctl.conf
vm.swappiness = 10
저장 후 재부팅 없이 변경 사항을 적용하려면 다음을 사용하십시오:
sudo sysctl -p
메모리 집약적인 데이터베이스의 경우 1에서 10이 일반적인 시작점입니다. 이것을 규칙으로 취급하지 마십시오. PostgreSQL이나 MySQL/InnoDB처럼 자체 버퍼 캐시가 있는 데이터베이스는 일반적으로 스왑을 피함으로써 이점을 얻습니다. 파일 서버는 더 큰 페이지 캐시를 선호할 수 있습니다. RAM이 너무 적은 소규모 VM은 어떤 숫자를 선택하든 문제가 발생합니다.
2. vfs_cache_pressure
vfs_cache_pressure는 커널이 디렉터리 및 inode 메타데이터(VFS 캐시)에 사용되는 메모리를 얼마나 적극적으로 회수할지 제어합니다.
- 이 값의 범위는 0에서 1000까지입니다.
- 기본값은 일반적으로 100입니다.
값이 100이면 커널은 VFS 캐시 메모리 회수와 페이지 캐시(디스크 데이터)에 사용되는 메모리 회수 간의 균형을 맞춥니다. 값 100은 메모리 압력이 있을 때 커널이 페이지 캐시 메모리 1부분마다 inode/dentry 캐시 메모리의 1부분을 회수하려고 시도함을 의미합니다.
vfs_cache_pressure 조정
- 값 증가(예: > 100): 커널이 VFS 캐시 메모리를 더 적극적으로 회수하도록 만듭니다. 이렇게 하면 RAM이 더 빨리 확보되지만, 메타데이터를 디스크에서 다시 읽어야 하므로 후속 파일 시스템 조회 속도가 느려질 수 있습니다.
- 값 감소(예: < 100): 커널이 VFS 캐시 회수를 더 보수적으로 만들도록 합니다. 이렇게 하면 디렉터리 및 inode 정보가 메모리에 더 오래 유지되어 반복적인 파일 시스템 작업 속도가 빨라집니다.
vfs_cache_pressure를 낮춰야 하는 경우:
시스템이 동일한 대규모 디렉터리 구조(복잡한 애플리케이션, 컨테이너 오케스트레이션 또는 특정 네트워킹 설정에서 일반적)에 자주 액세스하는 경우 이 값을 낮게(예: 50) 설정하면 메타데이터를 RAM에서 즉시 사용할 수 있게 하여 성능을 향상시킬 수 있습니다.
vfs_cache_pressure를 높여야 하는 경우:
시스템이 일반적인 메모리 압력으로 어려움을 겪고 있고 커널이 사용되지 않는 메모리를 신속하게 회수하기를 원한다면 이 값을 높일 수 있지만, 낮추는 것보다 덜 일반적입니다.
현재 값 확인 방법:
cat /proc/sys/vm/vfs_cache_pressure
영구적으로 값 변경 방법:
/etc/sysctl.conf 편집:
# /etc/sysctl.conf
vfs_cache_pressure = 50
sudo sysctl -p로 변경 사항을 적용하십시오.
경고: 매우 낮은
vfs_cache_pressure값은 커널이 예상보다 오래 디렉터리 및 inode 캐시를 보유하게 할 수 있습니다. 이는 메타데이터가 많은 워크로드에 도움이 될 수 있지만, 애플리케이션의 메모리 압력을 악화시킬 수도 있습니다. 효과를 측정하지 않은 경우 극단적인 값은 피하십시오.
종합 튜닝 시나리오
이러한 매개변수의 올바른 조합을 선택하면 애플리케이션 안정성과 파일 시스템 캐싱 간의 균형을 최적화할 수 있습니다.
시나리오 1: 데이터베이스 서버(메모리 우선)
목표: 애플리케이션 메모리 상주 시간 최대화; 어떤 대가를 치르더라도 스와핑 최소화.
vm.swappiness = 5vfs_cache_pressure = 50(디렉터리 데이터를 어느 정도 캐시하지만, RAM이 부족해지면 VFS 메타데이터보다 애플리케이션 메모리를 우선시).
변경하기 전에 데이터베이스가 실제로 스와핑되고 있는지 확인하십시오:
free -h
vmstat 1
grep -E 'pswpin|pswpout' /proc/vmstat
쿼리 지연 시간 급증 중에 스왑인 및 스왑아웃 카운터가 증가하는 경우 swappiness를 낮추면 도움이 될 수 있습니다. 스왑이 사용되지 않고 데이터베이스가 느리다면 swappiness가 문제가 아닙니다. 대신 쿼리 계획, 버퍼 적중률, 체크포인트, 디스크 지연 시간 및 연결 압력을 살펴보십시오.
시나리오 2: 높은 디스크 I/O 서버(캐싱 우선)
목표: 자주 액세스하는 파일 데이터를 페이지 캐시에 유지하여 디스크 성능 최대화.
vm.swappiness = 80(디스크 캐시 확장을 위해 RAM을 확보하기 위해 더 일찍 스와핑을 허용).vfs_cache_pressure = 100(inode와 페이지 캐시 간의 표준 균형).
이것은 사람들이 가장 자주 과도하게 튜닝하는 시나리오입니다. 서버가 동일한 파일을 반복해서 주로 읽는 경우 페이지 캐시가 중요합니다. 그러나 시스템이 캐시를 보존하기 위해 활성 작업자 프로세스를 스와핑하기 시작하면 파일 시스템 캐시가 정상으로 보이더라도 사용자는 더 나쁜 지연 시간을 경험할 수 있습니다. 캐시 크기뿐만 아니라 애플리케이션 응답 시간을 주시하십시오.
시나리오 3: 가상화 호스트 또는 범용 시스템
목표: 여러 워크로드에서 안정적인 성능.
vm.swappiness = 30(기본값 60보다 활성 VM/프로세스를 RAM에 약간 더 오래 유지하지만 제어된 스와핑을 여전히 허용하는 중간 설정).vfs_cache_pressure = 100(기본값이면 충분한 경우가 많음).
가상화 호스트는 게스트 메모리 동작이 호스트 수준 튜닝을 오도할 수 있으므로 추가 주의가 필요합니다. 벌루닝, 오버커밋 및 게스트 스왑이 모두 상호 작용할 수 있습니다. 게스트 메모리를 많이 스와핑하는 호스트는 각 게스트가 자신의 워크로드가 정상이라고 생각하더라도 VM 내부에 고통스러운 지연 시간을 만들 수 있습니다.
더 안전한 튜닝 워크플로
/etc/sysctl.conf를 편집하는 것부터 시작하지 마십시오. 설정이 관련이 있음을 먼저 증명하십시오.
정상 부하 중에 기준을 캡처하십시오:
free -h vmstat 1 10 cat /proc/sys/vm/swappiness cat /proc/sys/vm/vfs_cache_pressure느린 기간 동안 동일한 데이터를 캡처하십시오. 프로세스 수준 메모리를 추가하십시오:
ps -eo pid,comm,rss,vsz,%mem --sort=-rss | head -20하나의 값을 임시로 변경하십시오:
sudo sysctl vm.swappiness=10동작을 관찰할 수 있을 만큼 충분히 오래 워크로드를 실행하십시오. 더 낮은 스왑 활동, 더 나은 애플리케이션 지연 시간 및 새로운 파일 시스템 속도 저하가 없는지 확인하십시오.
현실적인 테스트 기간을 견딘 후에만 값을 영구적으로 만드십시오.
/etc/sysctl.d/를 사용하는 시스템에서는 /etc/sysctl.conf에 추가하는 것보다 작은 전용 파일이 더 깔끔한 경우가 많습니다:
sudo tee /etc/sysctl.d/90-memory-tuning.conf >/dev/null <<'EOF'
vm.swappiness = 10
vm.vfs_cache_pressure = 100
EOF
sudo sysctl --system
구성 관리 시스템이 sysctl 설정을 소유하는 경우 대신 해당 시스템에 변경 사항을 넣으십시오. 한 서버에서 수동으로 sysctl을 편집하면 잊어버리기 쉽고 재현하기 어렵습니다.
free -h를 당황하지 않고 읽기
일반적인 free -h 출력은 free 아래에 작은 숫자와 buff/cache 아래에 큰 숫자를 표시할 수 있습니다. 이는 정상입니다. 리눅스는 최근에 사용된 파일 데이터를 메모리에 유지합니다. 사용되지 않은 RAM은 아무에게도 도움이 되지 않기 때문입니다.
available, 스왑 사용량 및 현재 스왑 활동이 발생하는지 여부에 초점을 맞추십시오. 서버는 과거 메모리 급증으로 인해 할당된 스왑이 있지만 현재 스왑 변동이 없을 수 있습니다. 이는 지속적으로 스왑 인/아웃을 수행하는 서버보다 덜 긴급합니다.
다음을 사용하십시오:
vmstat 1
정상 부하에서 si와 so가 0에 가깝게 유지되면 스왑이 그 순간에 지연 시간을 적극적으로 유발하지 않는 것입니다. 애플리케이션이 중단되는 동안 0이 아닌 상태로 유지되면 메모리 압력이 심각한 용의자입니다.
이러한 설정을 조정하지 말아야 할 경우
swappiness 또는 캐시 압력을 변경하는 것이 잘못된 첫 번째 수정인 경우가 몇 가지 있습니다.
서버에 스왑이 구성되지 않은 경우 vm.swappiness는 실질적인 효과가 거의 없습니다. 정책 일관성을 위해 여전히 조정할 수 있지만, 그 자체로 메모리 압력을 해결하지는 않습니다.
스왑이 작은 비상 파티션으로만 존재하는 경우 설정이 도움이 될 수 있는 여지도 제한적입니다. 커널은 스왑을 사용할 시기를 선택할 수 있지만, 수백 메가바이트의 비상 공간을 실제 메모리 계층으로 바꿀 수는 없습니다. 해당 설정에서는 OOM 위험 및 서비스 제한에 초점을 맞추십시오.
프로세스에 실제 메모리 누수가 있는 경우 swappiness를 낮추면 고통이 지연됩니다. 누수는 계속 증가할 것입니다. 서비스를 다시 시작하면 일시적으로 용량을 복원할 수 있지만, 지속적인 수정은 애플리케이션 수준입니다: 누수 패치, 메모리 제한, 동시성 감소 또는 워크로드 변경.
디스크 장애, 스토리지 제한 또는 포화된 클라우드 볼륨으로 인해 디스크가 느린 경우 메모리 튜닝으로 일부 읽기를 줄일 수 있지만 스토리지 결함을 해결하지는 못합니다. iostat, 커널 로그, 클라우드 볼륨 메트릭 및 SMART/NVMe 상태를 확인하십시오.
작업 세트가 RAM보다 큰 경우 완벽한 sysctl 값은 없습니다. 더 많은 메모리, 더 적은 동시성, 더 작은 캐시, 다른 데이터 레이아웃 또는 워크로드 분할이 필요합니다.
컨테이너 및 Kubernetes 참고 사항
컨테이너에서 메모리 튜닝은 더 까다로워집니다. 호스트에 여유 RAM이 있더라도 컨테이너는 cgroup 메모리 제한에 도달할 수 있습니다. 호스트의 swappiness 설정은 여전히 중요하지만, 즉각적인 증상은 Pod 또는 컨테이너 내부의 OOM 종료일 수 있습니다.
cgroup 및 오케스트레이터 신호를 확인하십시오:
dmesg -T | grep -i 'killed process'
docker stats
kubectl describe pod <pod-name>
Kubernetes의 경우 노드 수준 sysctl 변경은 일회성 셸 세션이 아닌 노드 풀 구성의 일부여야 합니다. 또한 일부 sysctl은 네임스페이스화되고 일부는 노드 수준이라는 점을 기억하십시오. vm.swappiness와 vm.vfs_cache_pressure는 일반적인 리눅스 시스템에서 호스트 수준 설정이므로 변경하면 해당 노드의 모든 워크로드에 영향을 미칩니다.
모니터링 및 검증
변경 사항을 적용한 후에는 영향을 검증하기 위해 지속적인 모니터링이 중요합니다. free, vmstat 및 시스템 성능 모니터링 대시보드와 같은 도구를 사용하십시오.
vmstat 사용:
si(스왑 인) 및 so(스왑 아웃) 열을 모니터링하십시오. swappiness가 낮은 정상 시스템은 정상 부하에서 si 및 so에 대해 낮거나 0 값을 표시해야 합니다.
vmstat 5 10
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----\ r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 123456 102400 5123456 0 0 0 5 40 70 1 1 98 0 0
swappiness를 줄인 후에도 so 값이 계속 높게 유지되면 워크로드에 더 많은 사용 가능한 메모리 또는 더 낮은 메모리 요구 사항이 필요할 가능성이 높습니다. 더 많은 RAM이 하나의 답이지만 유일한 답은 아닙니다. 작업자 수를 줄이거나, 애플리케이션 캐시를 축소하거나, 데이터베이스 메모리를 조정하거나, 누수를 수정하거나, 서비스를 여러 호스트에 분할할 수도 있습니다.
vm.swappiness와 vm.vfs_cache_pressure를 범용 업그레이드가 아닌 워크로드 선호도로 취급하십시오. 실용적인 경로는 지루하지만 신뢰할 수 있습니다: 현재 스왑 및 회수 동작을 측정하고, 하나의 설정을 변경하고, 실제 부하에서 테스트하고, 애플리케이션 동작이 개선되는 경우에만 변경 사항을 유지하십시오.