페이지 교체가 너무 잦아 CPU가 일은 안 하고 페이징만 하는 상태(thrashing).
어떻게 빠지는가 — 악순환
메모리 부족 → 페이지 폴트 증가
↓
프로세스들이 디스크 I/O를 기다리며 블로킹
↓
CPU 사용률이 떨어진다
↓
스케줄러: "CPU가 놀고 있네? 프로세스를 더 올리자" ← 치명적 오판
↓
메모리가 더 부족해진다 → 페이지 폴트 더 증가
↓
⟳ 악순환
CPU 사용률을 보고 판단하는 것이 오히려 상황을 악화시킨다는 점이 이 현상의 핵심이다.
증상 — 지표로 알아보기
- CPU 사용률 — : 매우 낮음 (10% 미만)
- 디스크 I/O — : 100% 포화
- 시스템 반응 — : 거의 멈춤. 마우스도 안 움직임
- vmstat의 si/so — : 계속 큰 값 ← 결정적 증거
"CPU는 노는데 시스템은 멈춰 있다" 가 스래싱의 서명이다.
왜 생기나 — 워킹셋 이론
워킹셋이란 프로세스가 최근 일정 시간 동안 실제로 접근한 페이지들의 집합이다. "지금 당장 필요한 메모리"라고 보면 된다.
- 모든 프로세스의 워킹셋 합 ≤ 물리 메모리 — → 정상
- 모든 프로세스의 워킹셋 합 > 물리 메모리 — → 스래싱
각 프로세스가 자기 워킹셋조차 메모리에 못 두면, 방금 내보낸 페이지를 곧바로 다시 불러오는 일이 반복된다.
대응
| 방법 | 내용 |
|---|---|
| 다중 프로그래밍 정도 낮추기 | 프로세스 수를 줄인다 (직관과 반대) |
| 워킹셋 모델 | 각 프로세스의 워킹셋을 측정해 그만큼 프레임 보장 |
| PFF(페이지 폴트 빈도) | 폴트율이 높으면 프레임 추가, 낮으면 회수 |
| 메모리 증설 | 근본적이지만 즉효는 아님 |
| 스왑 끄기 | 스래싱 대신 빠르게 OOM으로 실패시킨다 |
서버 운영에서의 스래싱
① 컨테이너에서는 스왑을 끄는 것이 정석
스왑 켜짐 → 느리게 죽어 간다. 원인 파악도 어렵다 스왑 꺼짐 → OOM Killer가 즉시 죽인다 → 재시작되어 서비스 복구 "느리게 아픈 것보다 빨리 죽고 재시작되는 것이 낫다" 는 판단이다. 쿠버네티스가 기본적으로 스왑을 끄는 이유이기도 하다.
② JVM 힙이 물리 메모리를 넘으면 GC가 힙 전체를 순회할 때 모든 페이지를 건드리므로 워킹셋이 힙 전체가 된다. 스왑에 걸치면 GC 한 번에 수십 초가 걸려 사실상 장애다.
-Xmx는 (컨테이너 메모리 - 비힙 영역)보다 확실히 작게
③ 페이지 캐시와의 혼동
free -m에서 buff/cache가 큰 것은 정상이다. 필요하면 즉시 회수된다.
available 값을 봐야 한다.
캐시 스탬피드와 헷갈리지 말 것
이름이 비슷한 현상들이 있다.
- 스래싱 — 메모리 부족으로 페이징만 반복
- 캐시 스탬피드 — 캐시 만료 순간 요청이 DB로 몰림
- 라이브락 — 계속 움직이는데 진전이 없음
셋 다 "바쁜데 일이 안 된다"는 공통점이 있지만 원인과 층위가 다르다.