사전 vmstat
인터페이스

vmstat

gabury1고친 사람 github-actions[bot]

vmstat 은 서버의 자원 상태를 몇 초마다 한 줄씩 찍어 주는 명령입니다. 계산이 밀리는지, 메모리가 모자란지, 디스크를 기다리는지를 한 화면에 함께 보여 줍니다. 서버가 느려졌을 때 어느 자원이 막혔는지 가장 먼저 가늠해 보는 진단 명령입니다.

쉽고 빠른 이해

vmstat 은 기계 전체가 얼마나 바쁜지를 시간 순으로 찍는 명령입니다. CPU(Central Processing Unit, 중앙 처리 장치)는 계산을 맡는 장치입니다. vmstat 1 을 치면 1초마다 「돌고 싶은 프로세스가 6개, CPU 가 쉰 시간은 2%」 같은 줄이 하나씩 붙습니다.

서버가 느릴 때 원인은 CPU, 메모리, 디스크 어디든 될 수 있습니다. 이 명령이 없으면 도구를 하나씩 바꿔 가며 짐작으로 좁혀야 합니다.

  1. 커널이 세어 둔 숫자를 정한 간격마다 읽습니다
  2. 그 간격 동안 무슨 일이 얼마나 있었는지 셉니다
  3. 프로세스, 메모리, 스왑(메모리가 모자랄 때 내용을 옮겨 두는 디스크 공간), 디스크, 시스템, CPU 여섯 묶음을 한 줄에 찍습니다

대가가 있습니다. 기계 전체를 더한 값이라 어느 프로세스가 원인인지는 안 보입니다. 첫 줄은 지금이 아니라 부팅 뒤 평균이라 잘못 읽기 쉽습니다.

상세

vmstat 은 virtual memory statistics(가상 메모리 통계)를 줄인 이름입니다. 이름은 메모리를 말하지만 CPU 와 디스크 상태까지 함께 찍습니다. 리눅스와 FreeBSD 같은 유닉스 계열 운영체제에 들어 있는 명령입니다.

백엔드 개발자는 대개 서버가 느려졌을 때 이 명령을 꺼냅니다. 아직 이유를 모를 때입니다. 응답이 늦는 원인은 CPU 가 모자라서일 수 있습니다. 메모리가 모자라 디스크를 오가서일 수도 있습니다. 디스크 읽기를 기다리느라 멈춰 있을 수도 있습니다. vmstat 은 이 셋을 한 줄에 나란히 찍어 어느 쪽부터 파 볼지 정하게 해 줍니다.

이 절은 먼저 명령을 치는 법과 출력 모양을 봅니다. 그다음 여섯 칸 묶음을 하나씩 풉니다. 이어서 응답이 늦을 때 읽는 순서와 이 명령이 못 보는 것을 봅니다. 옵션과 칸 이름은 리눅스 기준입니다.

간격과 횟수

vmstat 은 숫자 두 개를 받습니다. 앞 숫자는 몇 초마다 찍을지, 뒤 숫자는 몇 번 찍을지입니다.

vmstat        # 한 줄만 찍고 끝
vmstat 1      # 1초마다, 끊을 때까지
vmstat 2 5    # 2초마다 5줄

간격만 주면 Ctrl+C 로 끊을 때까지 계속 찍습니다. 진단할 때는 흔히 vmstat 1 을 띄워 두고 수십 초 동안 숫자가 어떻게 움직이는지 봅니다.

출력 모양

아래는 CPU 가 넷인 서버에서 vmstat 1 3 을 친 모습입니다. 숫자는 예로 지어낸 것입니다.

터미널
$ vmstat 1 3
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0      0 812340  65432 2345678    0    0     5    12   80  150  3  1 96  0  0
 6  0      0 810112  65432 2345690    0    0     0    48 2100 5400 88 10  2  0  0
 5  0      0 809980  65432 2345702    0    0     0    16 2050 5300 90  9  1  0  0

맨 위 줄은 칸을 여섯 묶음으로 가르는 머리말입니다. 둘째 줄이 칸 이름입니다. 그 아래 세 줄이 값입니다.

칸마다 세는 대상과 단위가 달라서 숫자를 칸끼리 견주지는 않습니다. 같은 칸이 줄마다 어떻게 움직이는지를 봅니다. 아래 소절에서 묶음을 하나씩 풉니다. 이 출력은 「응답이 늦을 때 읽는 순서」에서 다시 읽습니다.

첫 줄은 부팅 뒤 평균

첫 값 줄은 지금 상태가 아닙니다. 컴퓨터가 켜진 뒤로 지금까지의 평균입니다. 둘째 값 줄부터가 방금 지난 간격 동안의 값입니다.

위 출력의 첫 값 줄은 CPU 가 96% 쉬고 있습니다. 둘째 줄부터는 쉰 몫(id)이 2% 로 떨어졌습니다. 방금 1초 동안 CPU 가 거의 쉬지 못했다는 뜻입니다.

이 차이를 모르면 첫 줄만 보고 「한가하다」고 잘못 판단합니다. 며칠 동안 한가하던 서버는 방금 바빠져도 첫 줄의 평균이 거의 안 움직입니다. 그래서 간격 없이 vmstat 을 한 번 치는 것으로는 지금 무슨 일이 나는지 알 수 없습니다.

메모리 양을 적는 네 칸(swpd · free · buff · cache)만은 첫 줄에서도 그 순간의 값입니다. 네 칸의 뜻은 아래 memory 소절에서 풉니다.

procs — 실행을 기다리는 프로세스

CPU 하나는 한 순간에 프로세스 하나만 돌립니다. 돌고 싶은 프로세스가 CPU 보다 많으면 나머지는 차례를 기다립니다. 이렇게 기다리는 줄을 실행 대기열이라 부릅니다.

r 은 지금 도는 프로세스와 실행 대기열에서 기다리는 프로세스를 합친 수입니다. 그래서 r 이 CPU 개수보다 계속 크면 그 차이만큼 CPU 앞에 줄이 서 있는 것입니다. 위 예에서 CPU 넷에 r 이 6 이면 둘이 기다리는 중입니다.

b 는 CPU 가 아니라 입출력을 기다리며 멈춘 프로세스 수입니다. 디스크 읽기가 끝나야 다음 줄을 실행할 수 있는 프로세스가 여기 들어갑니다. 이 값이 계속 0 보다 크면 디스크나 네트워크로 붙인 저장소의 응답이 늦다는 신호입니다.

memory — 메모리를 어디에 썼나

메모리가 모자라면 커널은 한동안 안 쓰인 메모리 내용을 디스크로 옮겨 메모리를 비웁니다. 이때 쓰는 디스크 공간을 스왑이라 부릅니다. swpd 는 스왑으로 내려가 있는 양입니다.

free 는 아무 데도 안 쓰이고 비어 있는 메모리입니다. buff 와 cache 는 커널이 디스크 내용을 메모리에 담아 둔 양입니다.

디스크에서 읽는 데는 메모리보다 훨씬 오래 걸립니다. 그래서 커널은 한 번 읽은 파일 내용을 남는 메모리에 담아 두고 다음 읽기에 다시 씁니다. cache 칸은 이렇게 담아 둔 파일 내용, 곧 페이지 캐시의 양입니다.

디스크는 정해진 크기의 덩어리 단위로 읽고 씁니다. 이 덩어리를 블록이라 합니다. 커널은 파일을 거치지 않고 디스크의 블록을 그대로 메모리에 담아 두기도 합니다. 이렇게 블록째 담아 둔 메모리가 버퍼입니다. buff 칸이 그 양입니다.

리눅스는 남는 메모리를 캐시로 채워 두므로 오래 켜진 서버일수록 free 가 작습니다. 프로그램이 메모리를 더 달라고 하면 커널은 캐시를 비워서 내줍니다. 그래서 free 가 작다는 것만으로는 메모리가 모자란 것이 아닙니다. 모자란지는 다음 소절의 si 와 so 로 가립니다.

메모리 칸의 기본 단위는 KiB(kibibyte, 1024 바이트)입니다. -S M 을 붙이면 MiB(mebibyte, 1024×1024 바이트) 단위로 찍습니다.

swap — 디스크를 오가는 메모리

si 는 스왑에서 메모리로 다시 읽어 들인 양입니다. so 는 메모리에서 스왑으로 내보낸 양입니다. 둘 다 초당 값입니다.

이 두 칸이 메모리 부족의 가장 분명한 신호입니다. 프로그램들이 쓰려는 메모리가 실제 메모리보다 커지면 커널은 내보냈다 다시 들이기를 쉬지 않고 되풀이합니다. 그러면 CPU 가 남아도 모든 프로그램이 디스크를 기다리느라 느려집니다. 이 상태를 스래싱이라 부릅니다.

swpd 가 0 보다 크다는 것만으로는 문제가 아닙니다. 예전에 한 번 내보낸 뒤로 다시 안 쓰인 메모리일 수 있습니다. 볼 것은 si 와 so 가 줄마다 0 이 아닌 값으로 이어지는지입니다.

io — 디스크와 오간 양

디스크처럼 블록 단위로 읽고 쓰는 장치를 블록 장치라 합니다. bi 는 블록 장치에서 읽어 들인 양입니다. bo 는 블록 장치로 써 보낸 양입니다. 둘 다 초당 값입니다.

이 두 칸은 디스크가 얼마나 바쁜지 대략 보여 줍니다. 로그를 많이 쓰는 서버는 bo 가 커집니다. 큰 파일을 읽는 배치 작업은 bi 가 커집니다. bi · bo 를 어떤 단위로 세는지는 확인 못 했습니다(미확인). 숫자의 크기보다 0 인지, 평소보다 큰지로 읽습니다. 디스크 장치마다 나눠 보려면 iostat 을 씁니다.

system — 인터럽트와 문맥 교환

인터럽트는 장치가 CPU 에게 「일이 생겼다」고 알리는 신호입니다. 네트워크 카드에 패킷이 도착하거나 디스크 읽기가 끝나면 인터럽트가 옵니다. in 은 초당 인터럽트 수입니다. 시계가 정해진 간격마다 보내는 인터럽트도 이 수에 들어갑니다.

CPU 가 돌리던 프로세스나 스레드를 멈추고 다른 것으로 바꿔 돌리는 일을 문맥 교환이라 합니다. 바꿀 때마다 지금 상태를 저장하고 다음 것의 상태를 불러와야 해서 쓸모 있는 일 없이 시간이 듭니다. cs 는 초당 문맥 교환 수입니다.

cs 가 평소보다 크게 뛰면 흔히 스레드가 너무 많거나 락을 두고 다투는 일이 잦을 때입니다. 락은 여러 스레드가 한 자원을 한 번에 하나씩만 쓰게 막는 잠금입니다. 락을 못 잡은 스레드는 잠들었다 깨기를 되풀이합니다. 그때마다 문맥 교환이 일어납니다. 얼마가 많은 것인지는 서버마다 달라서 평소 값과 견주어 봅니다.

cpu — CPU 시간을 어디에 썼나

CPU 는 프로그램 자신의 코드를 돌린 시간과 커널의 코드를 돌린 시간을 나눠 셉니다. 프로그램 자신의 코드를 도는 상태를 사용자 모드라 부릅니다. 이 시간이 us 칸입니다.

커널의 코드를 도는 상태는 커널 모드라 부릅니다. 이 시간이 sy 칸입니다.

프로그램이 파일을 읽거나 네트워크로 보내려면 시스템 콜로 커널에 부탁해야 합니다. 그동안은 커널 모드로 돕니다. 시스템 콜이 잦은 프로그램일수록 sy 가 커집니다.

wa 는 헷갈리기 쉬운 칸입니다. CPU 가 할 일이 없어 쉬는 시간 가운데 입출력을 기다리는 프로세스가 있던 시간을 wa 로 셉니다. 그러니 wa 는 CPU 가 바쁜 시간이 아니라 쉬는 시간의 한 갈래입니다. CPU 가 다른 일로 바쁘면 디스크를 기다리는 프로세스가 있어도 wa 가 안 오릅니다.

클라우드 서버는 대개 물리 서버 한 대를 나눠 쓰는 가상 머신입니다. 물리 CPU 는 그 위의 가상 머신들이 번갈아 씁니다. st 는 내 가상 머신에 돌 일이 있는 동안 물리 CPU 가 다른 가상 머신을 돌리느라 못 돈 시간입니다. 이름은 steal(빼앗김)에서 왔습니다.

다섯 칸은 CPU 시간을 나눈 백분율이라 더하면 100 이 됩니다. 칸마다 크면 의심할 것은 아래와 같습니다.

칸 뜻 크면 의심할 것
us 사용자 모드로 프로그램 코드를 돈 시간 애플리케이션의 계산이 많다
sy 커널 모드로 돈 시간 시스템 콜이나 문맥 교환이 너무 잦다
id 쉰 시간 작을수록 CPU 가 바쁘다
wa 쉬는 동안 입출력을 기다린 프로세스가 있던 시간 디스크가 요청을 다 못 받아 밀려 있다
st 다른 가상 머신에게 빼앗긴 시간 같은 물리 서버의 이웃이 CPU 를 많이 쓴다

판에 따라 vmstat 은 맨 끝에 gu 칸을 하나 더 찍습니다. 이 서버가 띄운 가상 머신의 코드를 돌린 시간입니다. 가상 머신을 띄우지 않는 서버에서는 늘 0 입니다. 이 칸이 붙을 때 여섯 칸을 더해 100 이 되는지는 확인 못 했습니다(미확인).

응답이 늦을 때 읽는 순서

칸이 많아서 읽는 순서를 정해 두면 덜 헷갈립니다. 아래 그림은 흔히 쓰는 순서입니다.

flowchart TD
    A{"vmstat 1 에서 si · so 가 계속 0 이 아닌가"}
    A -->|"그렇다"| B["메모리 부족 · 스왑을 오가고 있다"]
    A -->|"아니다"| C{"r 이 CPU 개수보다 계속 큰가"}
    C -->|"그렇다"| D["CPU 부족 · us 가 크면 애플리케이션, sy 가 크면 커널 쪽"]
    C -->|"아니다"| E{"wa 가 크고 b 가 0 보다 큰가"}
    E -->|"그렇다"| F["디스크 대기 · iostat 으로 장치를 본다"]
    E -->|"아니다"| G["자원은 여유 · 락이나 외부 호출을 본다"]

메모리를 먼저 보는 까닭이 있습니다. 스왑을 오가기 시작하면 wa 와 b 가 함께 오르고 CPU 칸도 흔들립니다. 디스크부터 보면 메모리 문제를 디스크 문제로 잘못 읽게 됩니다.

자원이 모두 여유로운 채로 느리면 문제는 이 서버 밖에 있기 쉽습니다. 프로세스는 락이나 데이터베이스, 다른 서비스의 응답을 기다리는 동안 CPU 도 디스크도 거의 안 씁니다. 클라우드 서버라면 st 도 함께 봅니다. st 가 계속 크면 내 프로그램과 상관없이 CPU 를 덜 받고 있는 것입니다.

「출력 모양」의 예를 이 순서로 읽어 봅니다. si 와 so 는 0 이라 메모리는 넉넉합니다. r 이 6 과 5 로 CPU 넷보다 큽니다. us 는 88 과 90 입니다. 애플리케이션 코드가 CPU 를 다 쓰고도 모자라 줄을 서는 상태입니다.

자주 붙이는 옵션

간격과 횟수 말고 진단에 흔히 쓰는 옵션 넷은 아래와 같습니다.

옵션 하는 일
-S M 메모리 칸을 MiB 단위로 찍는다. si · so · bi · bo 는 안 바뀐다
-w 칸을 넓혀 찍는다. 메모리가 큰 서버에서 숫자가 옆 칸으로 밀리지 않는다
-t 줄마다 찍은 시각을 붙인다
-s 한 줄씩 찍지 않고 누적 통계를 표로 한 번 찍는다

-t 는 출력을 파일로 남겨 두고 나중에 장애 시각과 맞춰 볼 때 씁니다.

vmstat 이 못 보는 것

vmstat 은 기계 전체를 더한 값만 찍습니다. CPU 가 바쁘다는 것은 알려 줘도 어느 프로세스가 바쁘게 했는지는 안 알려 줍니다.

CPU 칸도 모든 CPU 를 평균 낸 값입니다. CPU 가 열여섯인 서버에서 스레드 하나가 CPU 하나를 다 써도 us 는 6 남짓입니다. 그래서 「CPU 가 한가하다」는 결론은 CPU 마다 나눠 본 뒤에 내립니다.

vmstat 으로 어느 자원인지 가늠한 다음은 나눠 보는 명령이 맡습니다.

명령 알려 주는 것
vmstat 기계 전체의 CPU · 메모리 · 스왑 · 디스크 · 문맥 교환 흐름
top 프로세스마다 쓰는 CPU 와 메모리
mpstat CPU 하나하나의 바쁜 정도
pidstat 프로세스마다의 CPU · 입출력 · 문맥 교환
iostat 디스크 장치마다의 읽기 · 쓰기와 바쁜 정도
sar 같은 종류의 값을 기록해 두었다가 지난 시각의 것을 다시 보기

관련 항목

vmstat 이 칸으로 보여 주는 커널 개념

실행 대기열 · 스왑 · 페이지 캐시 · 버퍼 · 블록 장치 · 인터럽트 · 문맥 교환 · 사용자 모드 · 커널 모드 · 시스템 콜 · 가상 메모리 · 프로세스 · 스레드

vmstat 으로 짚어 내는 자원 문제

포화 · 스래싱 · 스와핑 · 입출력 대기 · 스틸 시간 · OOM 킬러 · 락 경합

vmstat 과 진단을 나눠 맡는 명령과 그 도구 묶음

top · htop · iostat · mpstat · pidstat · sar · free · netstat · perf · sysstat · procps

vmstat 숫자를 읽는 성능 분석 틀

성능 · USE 방법 · 사용률 · 로드 애버리지 · PSI

vmstat 이 상태를 읽어 오는 운영체제와 가상화 계층

커널 · 운영체제 · Linux · FreeBSD · 가상 머신 · 하이퍼바이저

다른 이름: virtual memory statistics · vmstat 명령