VPS CPU steal time 확인 방법 및 원인 분석
vmstat의 st 항목을 통해 CPU steal time을 확인하고, 내 서버의 부하인지 이웃 게스트로 인한 간섭인지 구분하는 방법을 설명합니다. 하이퍼바이저가 물리 코어를 할당하지 못해 발생하는 성능 저하의 원인과 측정 원리를 상세히 다룹니다.
CPU steal time이 실제로 측정하는 것
CPU steal time은 가상 CPU가 실행 준비를 마쳤음에도 불구하고, 하이퍼바이저가 물리 코어를 다른 게스트에게 할당하여 대기해야 했던 시간의 비율입니다. 작업은 큐에 쌓여 있었고, 코어는 다른 곳에서 사용 중이었습니다. Linux는 이 사이클을 별도로 계산하여 st로 보고합니다. 이를 통해 "내 서버가 바쁜 상태"인지 "내 서버가 차례를 기다리는 상태"인지 구분할 수 있습니다.
이 차이를 구분하는 것이 바로 이 카운터가 존재하는 이유입니다. 자신의 프로세스가 CPU에서 소비하는 시간은 us(user) 또는 sy(system)으로 보고됩니다. 작업이 스토리지 때문에 차단된 시간은 wa(I/O wait)로 보고됩니다. 실행 가능한 상태로 런큐(run queue)에 머물러 있고, 대기 중인 I/O 작업이 없음에도 실행되지 못하는 vCPU(가상 CPU)는 st으로 보고됩니다. 스케줄링 결정은 한 단계 아래인 호스트에서 이루어지기 때문에, 서버 내부에서는 이 상태를 해결할 수 없습니다.
이는 하나의 물리 머신을 여러 게스트가 공유하는 방식에서 직접적으로 기인합니다. 가장 흔한 원인은 이웃 게스트입니다. 같은 노드에 있는 다른 게스트가 과도한 부하를 일으키면, 호스트는 코어를 나누어 할당합니다. 간과하기 쉬운 두 번째 원인도 있습니다. 많은 제공업체가 공유 vCPU를 물리 코어의 일부로 제한하며, 여러 하이퍼바이저에서는 이 강제된 제한을 게스트 내부에서 steal로 계산합니다. 따라서 높은 st 수치는 코어가 할당되지 않았음을 의미합니다. 하지만 그 코어를 누가 가져갔는지를 항상 알려주는 것은 아닙니다.
steal 수치가 산출되는 원리
커널은 호스트를 직접 볼 수 없으므로 스스로 steal을 측정할 수 없습니다. 하이퍼바이저가 커널에 이 정보를 전달합니다. KVM 환경에서 호스트는 vCPU별 카운터를 게스트와 공유하는 페이지에 기록하며, 게스트는 CONFIG_PARAVIRT_TIME_ACCOUNTING 옵션으로 빌드된 커널을 통해 이를 합산합니다. 모든 배포판 커널은 이 옵션을 포함하고 있습니다. Xen 역시 runstate 영역을 통해 동일한 정보를 보고합니다. 이 총합은 정확히 한 곳을 통해 사용자 공간(userspace)으로 전달됩니다.
head -1 /proc/stat해당 cpu 라인에는 부팅 이후 USER_HZ 틱 단위로 측정된 10개의 카운터가 user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice 순서로 포함되어 있습니다. Steal은 레이블 뒤의 여덟 번째 값입니다. vmstat, top, mpstat를 비롯한 모든 도구와 Prometheus 익스포터는 동일한 필드를 읽어 두 개의 샘플을 백분율로 변환합니다.
이와 관련하여 가장 중요한 결과가 하나 있습니다. 하이퍼바이저가 카운터를 내보내지 않으면 해당 필드는 영원히 0으로 유지되며, 호스트에 부하가 걸려 있는 상황에서도 이를 기반으로 하는 모든 도구는 평온한 0.0 상태를 보고합니다. KVM과 Xen은 이 값을 내보내지만, VMware나 Hyper-V의 게스트는 보통 0으로 고정된 값을 보고합니다. 0이라는 수치를 신뢰하기 전에 먼저 플랫폼을 확인하십시오.
systemd-detect-virt이 명령은 kvm, xen, vmware, microsoft와 같은 플랫폼 이름을 출력하며, 베어메탈 환경에서는 none를 출력합니다. 컨테이너 내부에서는 lxc, docker, podman과 같은 런타임 정보를 출력하는데, 이는 하부 머신이 아닌 컨테이너 자체에 대한 정보입니다. kvm 환경에서 0이 출력된다면 호스트가 자원을 원활하게 제공하고 있다는 확실한 증거입니다. 하지만 해당 필드를 채우지 않는 플랫폼에서 0이 출력된다면 이는 아무런 증거가 되지 못하며, 이 경우 실제 작업 수행 시간을 측정하여 경합 여부를 판단해야 합니다.
VPS에서 CPU steal time을 확인하는 방법
vmstat은 procps 패키지에 포함되어 있습니다. 거의 모든 Ubuntu 및 Debian VPS 이미지에 기본으로 설치되어 있지만, 일부 최소형 컨테이너 이미지에는 없을 수 있으므로 사용하기 전에 설치해야 합니다.
sudo apt-get update
sudo apt-get install -y procps
vmstat --version
vmstat 1 5vmstat --version를 실행하면 vmstat from procps-ng 4.0.4과 같은 줄이 출력됩니다. 이 내용이 출력된다면 도구가 설치된 것이며, 실제 커널 카운터 값을 읽어오는 중입니다. vmstat 1 5는 1초에 한 번씩, 총 5번 샘플을 수집합니다.
procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
r b swpd free buff cache si so bi bo in cs us sy id wa st gu
1 0 0 3216484 98304 1284360 0 0 4 18 62 110 3 1 96 0 0 0
2 0 0 3216232 98304 1284360 0 0 0 0 248 431 6 2 84 0 8 0오른쪽 cpu 블록에서 st 열을 찾으십시오. 최신 procps-ng 빌드에서는 KVM 게스트 시간을 나타내는 gu 열이 그 뒤에 추가되므로, st은 마지막이 아닌 오른쪽에서 두 번째에 위치합니다. 릴리스마다 위치가 변경될 수 있으므로 반드시 헤더 이름을 기준으로 열을 확인하십시오.
정확한 측정을 위해 두 가지 습관을 권장합니다. 첫 번째 데이터 줄은 부팅 이후의 평균값이므로 무시하고 그 이후의 줄을 읽어야 합니다. 또한 steal time은 불규칙하게 발생하므로 샘플 하나만으로는 측정할 수 없습니다. vmstat 1 60를 실행하고 1분 동안 지켜본 뒤 결론을 내리십시오.
top은 %Cpu(s) 요약 줄의 st라고 표시된 필드에서 동일한 수치를 보고합니다.
%Cpu(s): 6.2 us, 2.1 sy, 0.0 ni, 83.9 id, 0.0 wa, 0.0 hi, 0.3 si, 7.5 st코어별 상세 정보를 보려면 sysstat 옵션을 추가하십시오.
sudo apt-get install -y sysstat
mpstat -P ALL 1 5mpstat는 CPU당 한 줄씩 %steal 열을 포함하여 출력하며, 이를 통해 모든 vCPU가 영향을 받는지 아니면 특정 vCPU만 영향을 받는지 확인할 수 있습니다. 기술 지원 티켓에 필요한 기록을 남기려면 화면에서 읽는 대신 샘플을 파일로 저장하십시오.
date -u | tee -a ~/steal.log
mpstat -P ALL 1 5 | tee -a ~/steal.log문제가 의심되는 시간 동안 cron을 통해 해당 명령을 실행하십시오. 그러면 단순히 공급자에게 "어젯밤에 느렸다"고 말하는 대신, 정확히 문제가 발생한 10분간의 데이터를 제시할 수 있습니다.
steal 수치는 무엇을 의미합니까?
0.0이 일정하게 유지됨. 정상 상태이거나, 플랫폼에서 steal 수치를 전혀 보고하지 않는 경우입니다. 안심하기 전에systemd-detect-virt로 확인하십시오.- 몇 초 동안 지속되는 몇 퍼센트의 급증. 공유 노드에서는 정상입니다. 이웃한 노드에서 빌드가 시작되었거나 호스트가 백업을 실행 중일 수 있습니다.
- 공유 플랜에서 1~5퍼센트가 지속됨. 예상된 범위입니다. 공유 CPU는 가격에 그 성능이 반영되어 있습니다.
- 5~10퍼센트가 지속됨. 체감할 수 있는 속도 저하가 발생합니다. 증거를 기록하기 시작하고, 며칠에 걸쳐 같은 시간대의 수치를 비교하십시오.
- 시간 단위로 10퍼센트 이상 지속됨. 현재 워크로드에 비해 노드가 과도하게 할당된 상태입니다. 이 수준이라면 기술 지원 티켓을 발행하거나 서버 이전을 고려해야 합니다.
공유 플랜에서 steal 수치를 보장하는 제공업체는 없으므로, 이 수치들을 사양이라기보다는 참고 지표로 활용하십시오. 실행 중인 작업의 성격에 따라 판단해야 합니다. 야간 배치 작업은 15퍼센트의 steal이 발생해도 아무도 눈치채지 못할 수 있습니다. 반면 지연 시간에 민감한 서비스는 평균 수치가 경고 수준에 도달하기 훨씬 전부터 p99 지표에서 문제가 드러납니다. 이것이 바로 트레이딩 봇과 같이 지연 시간에 민감한 워크로드를 전용 코어에서 실행해야 하는 이유입니다.
Steal time은 어떤 비용을 발생시키는가?
계산은 간단합니다. CPU 시간의 s만큼을 빼앗기면, 고정된 양의 CPU가 필요한 작업은 완료까지 1 / (1 - s)배의 시간이 더 걸립니다. 60초의 CPU 시간이 필요한 작업의 경우를 보겠습니다.
The data behind this chart
[
{
"steal_percent": 0,
"wall_clock_seconds": "60.0"
},
{
"steal_percent": 3,
"wall_clock_seconds": "61.9"
},
{
"steal_percent": 8,
"wall_clock_seconds": "65.2"
},
{
"steal_percent": 15,
"wall_clock_seconds": "70.6"
},
{
"steal_percent": 25,
"wall_clock_seconds": "80.0"
},
{
"steal_percent": 40,
"wall_clock_seconds": "100.0"
}
]공유 플랜에서 흔히 볼 수 있는 3 퍼센트의 경우, 해당 작업은 60.0초가 아닌 61.9초가 걸립니다. 이 정도 차이로 티켓을 발행하는 사람은 없습니다. 8 퍼센트일 때는 65.2초가 됩니다. 40 퍼센트가 되면 동일한 작업에 100.0초가 필요하게 되며, 평소에 처리되던 큐가 쌓이기 시작합니다.
이 값들은 측정값이 아니라 계산된 수치입니다. 이 모델은 실행 가능한 단일 스레드가 존재하고 steal이 구간 전체에 고르게 분포한다고 가정합니다. 실제 서비스는 이 곡선보다 더 나쁘게 느껴지는 경우가 많은데, 이는 steal이 발생한 구간이 요청 처리 도중에 끼어들어 해당 요청을 기다리는 모든 작업에 지연을 전이시키기 때문입니다. 공식에 의존하지 않고 실제 수치를 얻으려면, VPS 벤치마크를 수행하십시오. 한산한 시간대와 바쁜 시간대에 각각 측정하여 두 구간 모두에 대한 st 값을 기록해야 합니다.
Steal인가, 아니면 다른 문제인가?
Steal은 다른 증상과 혼동하기 쉽습니다. vmstat 라인에서 카운터들을 함께 확인하십시오.
st는 높지만r및us가 낮게 유지되는 경우: 호스트가 코어를 할당하지 않는 상태입니다. 이것이 Steal입니다.r가 vCPU 개수를 훨씬 상회하고us은 높으며st이 0에 가까운 경우: 할당된 CPU 용량보다 더 많은 작업을 수행 중입니다.r과nproc의 출력 결과를 비교하십시오. 이는 이웃의 영향이 아니라 본인의 오버서브스크립션(oversubscription) 문제입니다.wa은 높지만st이 0에 가까운 경우: 작업이 스토리지에서 차단된 상태이며, 이는 다른 해결책이 필요한 별개의 문제입니다.- Load average는 높지만
st와us이 모두 낮은 경우: 로드 수치는 인터럽트 불가능한(uninterruptible) 작업도 포함하므로, 이는 보통 CPU보다는 장치 오류나 네트워크 마운트 지연을 의미합니다.
버스터블(Burstable) 플랜은 별도로 주의해야 합니다. 유휴 상태일 때 크레딧 잔액이 쌓이고 작업 중일 때 소모되며, 잔액이 소진되면 제공업체는 기본 속도로 제한합니다. 일부 플랫폼에서는 이 스로틀링(throttle)이 Steal로 보고되기도 합니다. 반면 내부에서 보이지 않는 플랫폼도 있으며, 이 경우 단순히 초당 처리 가능한 사이클이 줄어듭니다. 이웃의 문제라고 단정하기 전에 플랜 설명을 먼저 확인하십시오.
컨테이너에서 steal time이 0으로 표시되는 이유
Steal은 가상 머신(VM)의 속성이지 그 안에서 실행되는 컨테이너의 속성이 아닙니다. 사용자의 VPS에서 실행되는 Docker 컨테이너는 호스트의 /proc를 공유하므로, 컨테이너 내부에서 읽은 st 값은 VPS의 steal 값이며 이는 의도한 결과입니다. VPS로 판매되는 컨테이너 기반 가상화는 다르게 동작합니다. lxcfs이 적용된 환경에서는 컨테이너 내부의 /proc/stat이 cgroup 계정을 기반으로 합성되므로, steal 값은 구조적으로 0이 됩니다. 컨테이너 내부에서만 데이터를 수집하는 모니터링 스택은 물리적 호스트가 자원 부족에 시달리는 상황에서도 steal 값이 0으로 평온하게 유지되는 것처럼 표시할 수 있습니다.
컨테이너 내부에서 동일한 의미를 갖는 지표는 CPU 쿼터 스로틀링(CPU quota throttling)입니다. cgroup v2에서는 다음과 같습니다.
cat /sys/fs/cgroup/cpu.statnr_throttled은 그룹이 CPU 쿼터에 도달하여 제한이 적용된 횟수를 나타내며, throttled_usec는 프로세스가 정지된 총 시간을 나타냅니다. nr_throttled 값이 증가한다는 것은 프로세스가 실행 가능한 상태였음에도 실행되지 못했음을 의미하며, 이는 steal과 동일한 경험이지만 사용자가 직접 설정한 제한으로 인해 발생합니다. 호스트를 탓하기 전에 먼저 자신의 제한 설정을 확인하십시오. 특히 Docker compose 파일에 CPU 제한을 설정하고 VPS에서 서비스를 운영하는 경우에는 더욱 그렇습니다. 계층화된 가상화(Layered virtualisation)는 시간이 소실되는 지점을 하나 더 추가합니다. VPS 내부의 VM은 호스트의 steal과 VM 자체의 스케줄링 지연을 모두 겪기 때문입니다. VPS에서 중첩 가상화를 사용하는 경우 이 점을 유념하십시오.
지속적인 steal 발생 시 대응 방법
게스트 내부의 설정으로는 steal 문제를 해결할 수 없습니다. 스케줄러가 결정을 내리는 주체는 게스트 외부이기 때문입니다. 커널을 업그레이드해도 상황은 바뀌지 않습니다. Linux 커널 7.2에 추가된 캐시 인식 스케줄링은 할당받은 코어 내에서 작업을 재배치할 뿐, 이웃 인스턴스가 이미 점유한 CPU 사이클을 되찾아올 수는 없습니다. 실질적인 대응 방안은 다음 네 가지입니다.
먼저 증거를 수집하십시오. UTC 기준 타임스탬프, 각 현상의 지속 시간, 반복 빈도, 그리고 mpstat 명령 결과에서 특정 vCPU만 영향을 받는지 아니면 전체가 영향을 받는지 기록하십시오. 일주일간 기록한 샘플 데이터가 스크린샷 한 장보다 훨씬 가치 있습니다.
수집한 데이터를 바탕으로 티켓을 발행하십시오. 다음 두 가지를 직접 질문하십시오. 해당 시간대에 노드가 오버서브스크립션(oversubscription) 상태인지, 그리고 인스턴스를 다른 노드로 이전할 수 있는지 확인하십시오. vmstat 출력 결과와 정확한 발생 시간을 함께 첨부하십시오. 제공업체는 재현 가능한 시간대가 있을 때 움직입니다. 단순히 서버가 느리다는 내용의 티켓은 다시 정보를 요구하는 답변만 돌아올 뿐입니다. 이러한 작업을 얼마나 제공업체에 위임할 수 있는지가 관리형 VPS와 비관리형 VPS의 실질적인 차이 중 하나입니다.
마이그레이션을 요청하십시오. 게스트를 부하가 적은 노드로 옮기는 것은 제공업체 입장에서 일상적인 작업이며, 보통 짧은 재부팅으로 완료됩니다. 이는 비용이 들지 않으면서도, 우연히 여러 부하가 큰 인스턴스가 한 노드에 몰린 경우를 해결하는 가장 일반적인 방법입니다.
비용을 지불하여 경합을 제거하십시오. 전용 vCPU 플랜은 물리적 코어를 귀하의 인스턴스에 예약하므로, steal 카운터는 0으로 유지됩니다. 매달 비용은 더 발생하지만, 성능 변동을 허용할 수 없는 워크로드에 대한 정직한 해결책입니다. 만약 이것으로도 부족하거나 메모리 대역폭까지 독점하고 싶다면, 다음 단계는 VPS 대신 전용 서버를 사용하는 것입니다.
위의 조치를 기다리는 동안에는 steal로 인한 피해를 최소화하십시오. vCPU 개수보다 적은 수의 워커 스레드를 실행하십시오. 코어를 할당받지 못한 스레드는 컨텍스트 스위칭만 유발하기 때문입니다. 배치 작업은 직접 기록한 로그를 참고하여 노드가 한가한 시간대로 옮기십시오. 그 후 동일한 시간대에 같은 명령으로 다시 측정하십시오. 그러면 추측이 아닌, 변경 사항이 효과가 있었는지 명확히 말할 수 있습니다.
FAQ
VPS에서 정상적인 CPU steal time은 어느 정도입니까?
공유 플랜에서는 물리 코어를 여러 게스트가 나누어 사용하므로 짧은 스파이크나 5퍼센트 미만의 지속적인 수치는 정상입니다. 수 시간 동안 두 자릿수 이상의 수치가 지속된다면 정상적인 상황이 아니며, 지원 티켓을 생성해야 합니다. 전용 vCPU 플랜에서는 0.0이 정상 수치이므로, 이외의 값은 보고해야 할 오류입니다. 수치는 본인의 워크로드에 비추어 판단하십시오. 야간 배치 작업은 견딜 수 있는 steal 수치라도 지연 시간에 민감한 API는 견디지 못할 수 있습니다.
더 큰 플랜을 사용하면 높은 steal time 문제가 해결됩니까?
그 자체로는 해결되지 않습니다. 동일한 공유 노드에서 vCPU 개수를 늘리면 더 많은 가상 CPU가 동일한 물리 코어를 두고 경쟁하게 되며, 퍼센트 수치는 그대로 유지될 수 있습니다. steal time을 제거하는 방법은 전용 CPU를 할당받거나 부하가 적은 노드로 이동하는 것뿐입니다. 바쁜 장비의 더 큰 점유율을 가져도 여전히 바쁜 장비의 점유율일 뿐입니다.
서버가 분명히 느린데 왜 steal time이 0으로 표시됩니까?
두 가지 일반적인 이유가 있습니다. 하이퍼바이저가 카운터를 아예 내보내지 않는 경우인데, 이는 VMware 및 Hyper-V 플랫폼에서 흔히 발생하며 호스트의 상태와 관계없이 필드 값이 0으로 유지됩니다. systemd-detect-virt를 실행하여 사용 중인 플랫폼을 확인하십시오. 그렇지 않다면 병목 현상이 다른 곳에 있는 것입니다. wa를 통해 스토리지 대기 시간을 확인하고, r과 nproc을 비교하여 자체적인 과부하 여부를 점검하며, 컨테이너 내부의 /sys/fs/cgroup/cpu.stat을 읽어 쿼터 제한이 있는지 확인하십시오.
서버 내부에서 steal time을 줄일 수 있습니까?
게스트 내부에서 호스트의 스케줄링 방식을 변경할 수는 없습니다. 다만 그 영향력을 줄일 수는 있습니다. vCPU 개수보다 적은 수의 워커 스레드를 실행하여, 실행 큐에서 코어를 기다리는 작업량을 줄이십시오. 배치 작업은 노드가 한가한 시간대로 옮기십시오. 결과를 캐싱하여 CPU가 필요한 요청 자체를 줄이는 것도 방법입니다. steal time을 근본적으로 제거하는 노드 이전이나 전용 코어 할당은 제공업체 측에서 처리해야 할 영역입니다.