모니터링 대시보드의 CPU 사용률이 20~30%인데 애플리케이션 응답은 계속 느려지는 상황을 겪어본 적이 있을 것이다. 흔히 보는 시스템 전체 평균 %CPU는 여러 코어를 뭉뚱그린 값이라, 일부 코어만 100% 포화된 상태를 “아직 여유 있음”으로 왜곡해서 보여줄 수 있다. 사용률(utilization)과 포화도(saturation)는 다른 지표인데 하나로 뭉쳐 보면 이 차이가 감쪽같이 사라진다. 이 글에서는 일부러 코어 일부만 포화시켜 이 왜곡을 재현하고, PSI로 진짜 포화 여부를 확인하는 법을 정리한다.
Utilization과 Saturation
| 지표 | 의미 | 흔한 함정 |
|---|---|---|
| Utilization(사용률) | 리소스가 바쁜 시간의 비율 | 여러 코어를 평균 내면 일부 코어의 100%가 희석된다 |
| Saturation(포화도) | 리소스를 기다리는 작업이 쌓여 있는 정도(큐 길이) | 사용률만 보면 이 대기열 자체가 안 보인다 |
재현 — 코어 절반만 포화시키기
6코어 중 3개(0~2번)에만 무한 루프 프로세스 12개를 taskset -c 0-2로 몰아넣고 mpstat을 확인했다.
$ mpstat -P ALL 1
Average: CPU %usr ... %idle
Average: all 13.50 ... 85.93 ← 전체 평균만 보면 한가해 보임
Average: 0 98.08 ... 0.00
Average: 1 100.00 ... 0.00
Average: 2 100.00 ... 0.00
Average: 3 0.00 ... 100.00
Average: 4 0.00 ... 100.00
Average: 5 0.00 ... 98.69
all 행만 보면 13.5%로 여유가 넘쳐 보이지만, 코어별로 쪼개보면 0~2번은 완전 포화(98~100%)고 3~5번만 놀고 있다. 대시보드가 시스템 전체 평균만 보여준다면 이 포화 상태는 완전히 감춰진다.
run queue와 PSI로 포화도 직접 확인
$ vmstat 1
procs -----------memory---------- ---system-- -------cpu-------
r b swpd free buff cache in cs us sy id wa
13 1 13400 6576300 10876 914172 619 0 0 1 97 2
14 0 13400 6576608 10876 914220 751 410 14 0 84 2
12 0 13400 6577520 10876 914220 982 496 17 1 82 0
$ cat /proc/pressure/cpu
some avg10=53.64 avg60=14.49 avg300=20.31 total=486129702
$ uptime
load average: 1.08, 0.59, 0.46
| 지표 | 값 | 해석 |
|---|---|---|
vmstat의 r(run queue) | 12~14 | 동시에 실행 가능한(runnable) 프로세스 수. 코어 3개로는 이 중 3개만 동시에 처리 가능 |
PSI cpu some avg10 | 53.64% | 최근 10초 동안 최소 1개 태스크가 CPU를 못 받아 대기한 시간의 비율. 시스템 평균 사용률 13.5%와 정반대 신호 |
run queue 12~14는 코어 3개가 감당할 수 있는 수(최대 3)를 크게 웃돌고, PSI는 절반 넘는 시간 동안 뭔가가 CPU를 기다렸다고 정확히 알려준다. 사용률(13.5%)과 포화도(53.64%)가 이렇게 반대로 갈 수 있다는 게 이 글의 핵심이다.
대조 — 코어 수만큼만 배치한 정상 케이스
같은 실험을 프로세스 12개 대신 6개로, 코어 6개에 1:1로 배치해서 반복했다.
$ mpstat -P ALL 1
Average: all 85.71 ... %idle 0.00
$ cat /proc/pressure/cpu
some avg10=24.54 avg60=22.44 avg300=11.50
이번엔 all 사용률(85.71%)이 실제 부하를 정직하게 반영한다 — 코어마다 프로세스 하나씩이라 평균이 왜곡될 여지가 없다. PSI도 24.54%로, 앞선 12:3 케이스(53.64%)의 절반 이하로 떨어졌다. 사용률이 커져도 코어 수와 실행 가능한 작업 수가 맞아떨어지면 포화도는 오히려 낮아진다는 걸 확인할 수 있다.
주의사항
| 항목 | 내용 |
|---|---|
| PSI는 비교적 최근 기능 | 커널 4.20 이상, cgroup v2 환경에서 기본 제공. 오래된 커널이면 vmstat의 r 컬럼이나 코어별 mpstat으로 대체 |
| full vs some 구분 | some은 하나라도 대기 중이면 카운트, full은 모든 실행 가능 태스크가 동시에 막혀 CPU가 완전히 낭비된 시간만 카운트. 둘 다 확인할 것 |
| 평균 사용률 대시보드만 믿지 말 것 | 알림 임계값을 시스템 전체 평균 %CPU로만 걸어두면 이런 국소 포화를 놓친다. 코어별 최댓값이나 PSI 기반 알림을 병행할 것 |
| taskset/cpuset 오배치가 원인일 수 있다 | 이번 재현처럼 특정 코어에 프로세스가 몰리는 원인은 애플리케이션 설계보다 CPU affinity 설정 실수인 경우도 많다 |
마무리
시스템 전체 평균 사용률이 낮다고 여유가 있다고 단정하지 말 것. 코어별 mpstat, run queue 길이, 그리고 가능하면 PSI까지 함께 봐야 진짜 포화 상태인지 판단할 수 있다. USE 메소드(Utilization, Saturation, Errors)의 세 지표를 함께 보는 습관이 여기서 나온다.
참고
Brendan Gregg – USE Method: Linux Performance Checklist
Kernel.org – Pressure Stall Information (PSI)