본문 바로가기
일반IT/리눅스

🕵️‍♂️ 리눅스 디스크 I/O 병목 현상, 범인부터 장비까지 추적하기!

by gasbugs 2025. 10. 12.

안녕하세요! 리눅스 시스템을 운영하다 보면 갑자기 디스크 I/O가 급증하면서 시스템 전체가 느려지는 경험, 다들 한 번쯤 있으시죠? 🐢 이때 어떤 프로세스가 문제를 일으키는지, 그리고 그 프로세스가 실제로 어떤 물리 디스크에 부하를 주고 있는지 찾아내는 것은 정말 중요합니다.

 

오늘은 iotop이라는 강력한 도구를 활용해서 디스크 I/O를 많이 유발하는 프로세스를 찾아내고, 그 프로세스가 사용하는 파일 시스템을 거쳐 최종적으로 어떤 물리 디스크에 연결되어 있는지까지 추적하는 여정을 떠나보겠습니다! 🚀

 


📊 1단계: 가장 많은 디스크 읽기(Read)를 유발하는 프로세스 찾기

가장 먼저 시스템에 부하를 주는 원인을 특정해야 합니다. 디스크 I/O를 모니터링하는 데는 iotop 명령어가 매우 유용합니다. 만약 설치되어 있지 않다면 간단하게 설치할 수 있습니다.

# iotop이 설치되어 있지 않다면 설치합니다.
yum install -y iotop

 

이제 iotop을 배치 모드(-b)로 2번 실행(-n 2)해서, 현재 I/O가 있는 프로세스만(-o) 필터링합니다. 그 결과를 디스크 읽기(DISK READ) 기준으로 정렬해서 가장 높은 프로세스의 PID(프로세스 ID)를 찾아 파일에 저장해 보겠습니다.

# iotop을 배치 모드, 2회 반복, I/O가 있는 프로세스만 보도록 실행
# 결과를 디스크 읽기(4번째 컬럼) 기준으로 정렬하여 최상위 프로세스의 PID(1번째 컬럼)를 추출
PID_HIGH_READ=$(iotop -b -n 2 -o | tail -n +3 | sort -k4,4nr | head -n 1 | awk '{print $1}')

# 찾은 PID를 /opt/highread.pid 파일에 저장
echo ${PID_HIGH_READ} > /opt/highread.pid
  • iotop -b -n 2 -o: 자동화된 스크립트에서 사용하기 위해 배치 모드로 2회 정보를 수집합니다.
  • tail -n +3: iotop의 헤더 정보를 제외하고 실제 프로세스 목록만 가져옵니다.
  • sort -k4,4nr: 4번째 컬럼(DISK READ)을 기준으로 숫자 내림차순(nr) 정렬합니다.
  • head -n 1: 정렬된 결과 중 맨 위 첫 번째 줄만 가져옵니다. (가장 높은 프로세스)
  • awk '{print $1}': 첫 번째 컬럼인 PID만 추출합니다.

이제 /opt/highread.pid 파일을 열어보면 어떤 프로세스가 디스크를 가장 많이 읽고 있는지 바로 확인할 수 있습니다! 📈


🔄 2단계: 가장 잦은 I/O 트랜잭션을 유발하는 프로세스 찾기

단순히 읽기/쓰기 용량뿐만 아니라, I/O 작업의 빈도(IO%)가 높은 프로세스를 찾는 것도 중요합니다. 작은 파일을 수없이 읽고 쓰는 작업이 시스템에 더 큰 부하를 줄 수도 있기 때문이죠.

이번에는 I/O 사용률(10번째 컬럼)을 기준으로 정렬하여 가장 바쁜 프로세스를 찾아보겠습니다.

# iotop 결과를 I/O 사용률(10번째 컬럼) 기준으로 정렬하여 최상위 프로세스의 PID를 추출
PID_HIGH_TPS=$(iotop -b -n 2 -o | tail -n +3 | sort -k10,10nr | head -n 1 | awk '{print $1}')

이제 PID_HIGH_TPS 변수에는 가장 잦은 디스크 작업을 수행하는 프로세스의 ID가 저장되었습니다. 이 프로세스를 집중적으로 파헤쳐 보겠습니다! 🧐


🗺️ 3단계: 프로세스에서 물리 디스크까지의 경로 추적하기

이제 가장 흥미로운 부분입니다. 위에서 찾은 PID_HIGH_TPS 프로세스가 과연 어떤 파일에 접근하고, 그 파일은 어떤 파티션을 거쳐 어떤 물리 디스크에 저장되어 있는지 추적해 보겠습니다.

📝 3-1. 프로세스가 열고 있는 파일 찾기

lsof (List Open Files) 명령어를 사용하면 특정 프로세스가 현재 어떤 파일들을 열고 있는지 확인할 수 있습니다.

# lsof로 해당 PID가 열고 있는 파일 중 일반 파일(REG)의 경로를 찾음
FILE_PATH=$(lsof -p ${PID_HIGH_TPS} | awk '$4 ~ /REG/ {print $9}' | head -n 1)

 

위 명령어를 통해 프로세스가 현재 사용 중인 파일의 전체 경로(FILE_PATH)를 알아냈습니다.

 

🔗 3-2. 파일이 속한 장치(Device Mapper) 찾기

파일 경로를 알았으니, df 명령어로 해당 파일이 어떤 파일 시스템(마운트 포인트)에 속해 있는지 확인할 수 있습니다. LVM(Logical Volume Manager)을 사용하는 경우, 보통 /dev/mapper/ 형태의 논리 볼륨 이름이 나옵니다.

# df 명령어로 파일 경로가 속한 장치명을 찾음
DM_DEVICE=$(df ${FILE_PATH} | tail -n 1 | awk '{print $1}')

 

DM_DEVICE 변수에는 /dev/mapper/centos-root 와 같은 논리적인 장치명이 저장됩니다.

 

💿 3-3. 진짜 물리 디스크(Physical Device) 찾기!

마지막 단계입니다! 논리적인 장치명은 실제 물리 디스크를 가리키는 이름표와 같습니다. lsblk와 readlink를 조합하여 이 논리 볼륨이 어떤 물리 파티션 위에 만들어졌는지 최종적으로 확인할 수 있습니다.

# lsblk로 디바이스 매퍼 이름(DM_DEVICE)이 가리키는 실제 물리 파티션의 이름을 찾음
REAL_DEVICE_PARTITION=$(lsblk -no pkname $(readlink -f ${DM_DEVICE}))

# 최종적으로 찾은 물리 장치 경로를 파일에 저장
echo "/dev/${REAL_DEVICE_PARTITION}" > /opt/devname.txt
  • readlink -f ${DM_DEVICE}: 심볼릭 링크인 장치명의 원본 경로를 찾아줍니다.
  • lsblk -no pkname ...: 해당 장치의 부모 커널 이름(pkname), 즉 실제 물리 파티션 이름을 출력합니다. (sda2 등)

드디어 /opt/devname.txt 파일을 열어보면, 문제를 일으키던 프로세스가 최종적으로 사용하고 있는 물리 디스크 장치명(/dev/sda2 등)을 확인할 수 있습니다! 🎉


✨ 마무리하며

이렇게 iotop, lsof, df, lsblk와 같은 기본 리눅스 명령어들을 파이프라인으로 연결하여, 막연했던 디스크 부하의 원인을 구체적인 프로세스 ID부터 실제 물리 디스크까지 단계별로 추적하는 방법을 알아보았습니다.

이런 과정을 통해 시스템의 병목 지점을 정확히 파악하고, 디스크 교체나 데이터 재배치 등 더 효과적인 해결책을 마련할 수 있습니다. 여러분의 시스템에 문제가 생겼을 때, 이 방법을 활용하여 명탐정처럼 원인을 추적해보세요! 😉