와, 정말 실무적인 고민이시네요.
CPU나 메모리처럼 '사용량'으로 치부하기 쉬운 지표들만 보는 단계에서, 정말 서비스의 근본적인 병목 지점을 찾기 시작하신 것 같아 보기 좋습니다.
디스크 I/O 병목은 정말 잡기 까다롭기로 악명이 높아요.
왜냐하면 병목이 '하드웨어 자체의 한계'일 수도 있고, '어떤 애플리케이션이 어떻게 요청하는가'의 문제일 수도 있거든요.
그래서 단순히 iostat 몇 번 돌려보고 "아, 디스크가 바쁘네" 하고 끝내면, '바쁜 게 정상적인 바쁨'인지, 아니면 '비효율적인 바쁨'인 건지 구분이 안 되더라고요.
경험을 공유하자면, 이 문제는 보통 '지표 수집' → '분석 관점 전환' → '실제 트레이싱' 이 세 단계로 접근해야 합니다.
제가 사용해봤던 방법들을 몇 가지 단계별로 정리해 드릴게요.
혹시 지금 사용하시는 OS가 리눅스 기반이라면, 아래 툴들이 가장 강력한 무기가 될 거예요.
--- ### 1.
1단계: '무엇이' 디스크를 쓰는지 파악하기 (가장 먼저 해야 할 것) 디스크가 바쁘다는 건 알겠는데, 누가 바쁜 건지 알아야 해요.
단순히 iostat만 보면 r/s (초당 읽기 요청 수), w/s (초당 쓰기 요청 수) 같은 걸 보게 되는데, 이 숫자가 높아도 그게 병목의 원인인지 아닌지 판단하기 어려울 때가 많습니다.
여기서는 **'프로세스 관점'**에서 접근해야 합니다.
추천 툴 및 방법: * iotop: 이건 정말 필수입니다.
- 실시간으로 어떤 프로세스가 가장 많은 디스크 I/O를 발생시키고 있는지 보여줍니다.
- CPU 사용량과 함께 보면, "CPU는 적게 쓰는데, 특정 웹 서버 프로세스가 I/O를 독점하고 있네" 같은 가설을 세우는 데 결정적입니다.
- 주의점:
iotop이 없다면 sudo apt install iotop이나 배포판 패키지 매니저로 설치해야 할 수 있습니다.
그리고 이 툴 자체도 어느 정도의 샘플링 간격이 있기 때문에, 순간적인 트래픽 스파이크는 놓칠 수 있습니다.
pidstat -d (sysstat 패키지): * 이건 특정 프로세스 ID(PID)를 지정해서 디스크 I/O 통계를 주기적으로 뽑아주는 기능이 강력합니다.
iostat이 시스템 전체의 통계라면, pidstat -d <PID> 1 5 같은 명령어로 "이 프로세스만" 5초 동안 1초 간격으로 디스크 I/O를 추적할 수 있어요.
- 만약 여러 프로세스가 섞여서 문제라면,
top 명령어에서 + 키를 눌러 I/O 뷰를 활성화하거나, htop 같은 개선된 툴을 쓰는 것도 도움이 됩니다.
--- ### 2.
2단계: '어떤 종류의 I/O'가 문제인지 파악하기 (깊이 들어가기) 이제 누가 쓰는지 알았으니, 그 사용 방식 자체에 문제가 있는지 봐야 합니다.
이 부분이 가장 복잡한데, 여기서 **'읽기/쓰기 패턴'**과 **'지연 시간(Latency)'**을 봐야 합니다.
주요 체크 포인트: 1.
Sequential vs.
Random I/O: * 만약 로그 기록이나 대량의 데이터를 순차적으로 쓰는 작업(Sequential Write)이 주를 이룬다면, 디스크 쓰기 속도(Throughput)가 중요합니다.
- 하지만 데이터베이스 쿼리처럼 여기저기 흩어진 작은 데이터를 읽는 작업(Random Read/Write)이 주를 이룬다면, 디스크의 IOPS (Input/Output Operations Per Second) 성능이 중요합니다.
- 만약 요청의 특성이 랜덤인데 IOPS가 부족하다는 신호가 온다면, SSD의 종류(NAND 유형 등)나 LVM/RAID 구성을 재검토해봐야 할 수도 있습니다.
캐싱 문제: * 운영체제는 디스크 I/O를 줄이기 위해 캐싱을 엄청나게 활용합니다.
- 데이터베이스나 애플리케이션 레벨에서 캐싱 정책이 잘못되거나, 캐시된 데이터를 너무 자주 무효화(Invalidation)하는 작업이 반복되면, 실제 디스크 접근이 비정상적으로 늘어날 수 있습니다.
- 이런 경우, 단순히 '디스크가 느리다'가 아니라 **'캐시 히트율(Cache Hit Ratio)이 떨어진다'**는 관점에서 접근해야 합니다.
추가로 볼 지표: * vmstat: 메모리와 디스크 I/O의 관계를 볼 때 유용합니다.
si (swap in), so (swap out) 값이 지속적으로 높게 나온다면, 물리 메모리가 부족해서 스왑 영역까지 쓰고 있다는 뜻이니, 이게 I/O 병목의 1순위 원인일 수 있습니다.
b (블록 디바이스 사용량)이나 d (디스크 대기 시간)을 체크하여 시스템 전체의 I/O 대기열이 너무 길어지고 있는지 확인하세요.
--- ### 3.
3단계: 커널 레벨의 심층 분석 (최후의 수단, 강력 추천) 위의 툴들로도 원인이 모호할 때, '시스템 콜 레벨'에서 무슨 일이 벌어지는지 추적해야 합니다.
이게 가장 어렵고, 많이 이해해야 하는 부분이기도 합니다.
eBPF 및 BCC (BPF Compiler Collection) 활용: * 요즘 가장 강력하고 세밀한 방법론으로 각광받는 게 바로 eBPF 기반의 툴들입니다.
- 이 툴들은 커널 내부 함수 호출 레벨에서 원하는 이벤트를 가로채서(Hooking) 정보를 얻어낼 수 있게 해줍니다.
- 예를 들어, 특정 파일 시스템 호출(
vfs_read, vfs_write)가 발생할 때마다, 어떤 PID가, 어떤 파일 경로에, 어떤 크기의 데이터를, 어느 정도의 지연 시간으로 요청했는지를 거의 실시간으로 파악할 수 있습니다.
- 직접 커널 코드를 건드리는 건 아니지만, 커널의 깊숙한 곳의 동작 흐름을 감시한다는 점에서 기존 툴들과 차원이 다릅니다.
- 학습 커브: 이 영역은 진입 장벽이 높은 편입니다.
처음 시도하신다면, sysdig 같은 상용/오픈소스 툴들이 eBPF를 활용한 인터페이스를 제공하는지 먼저 찾아보시는 걸 추천합니다.
디버깅 흐름도: 1.
**iotop**으로 범인(Process)을 좁힌다.
**pidstat -d**로 그 범인이 어떤 종류의 I/O를 많이 하는지(읽기/쓰기 비율, IOPS/Throughput) 확인한다.
3.
여전히 원인이 불분명하면, **vmstat**으로 메모리/스왑 상황을 점검한다.
4.
최종적으로, 특정 API 호출 패턴을 의심한다면 eBPF 계열 툴로 트레이싱을 시도한다.
--- ###
실전에서 제가 자주 실수했던 부분과 팁 1.
'측정'과 '원인'을 혼동하지 마세요. * "디스크 I/O가 높다" $\rightarrow$ 증상 * "특정 API 호출이 대용량 파일 읽기를 유발한다" $\rightarrow$ 원인 * 실수: 증상을 보고 무조건 디스크 업그레이드를 고려함.
- 정정: 증상을 보고, 그 증상을 유발하는 **소프트웨어 로직(예: 쿼리 최적화, 캐시 미스 로직)**을 먼저 개선해야 함.
디스크 업그레이드는 로직 최적화 후, 여전히 병목이 남았을 때의 마지막 수단으로 아껴두는 게 좋습니다.
2.
트랜잭션 단위로 측정하세요. * 단순히 평균 부하만 보는 건 위험합니다.
- "A라는 요청을 보냈을 때, 응답까지의 총 지연 시간(Latency) 중, 디스크 I/O 대기 시간이 몇 ms를 차지하는가?"를 측정해야 합니다.
- 이건 APM 툴이나, 요청에 타임스탬프를 찍어 로그로 남긴 뒤, 로그 분석 툴(ELK 등)에서 해당 요청의 각 단계별 소요 시간을 재는 방식으로 접근하는 게 가장 정확합니다.
3.
데이터베이스 I/O는 별개로 취급하세요. * 대부분의 서비스 병목은 디스크 자체의 문제가 아니라, DB 엔진의 쿼리 비효율성에서 오기 때문입니다.
- DB 모니터링 툴을 쓰신다면, 디스크 I/O 외에 **'Slow Query Log'**와 'Locking/Blocking' 상황을 최우선으로 확인하는 게 10배는 더 도움이 될 수 있습니다.
- 디스크 I/O가 높아진 원인 80%는 결국 DB가 물리적으로 디스크에 접근할 수밖에 없는 상황(인덱스 누락, 테이블 스캔 등) 때문일 때가 많습니다.
결론적으로 말씀드리면, 지금 단계에서는 iotop과 pidstat -d를 조합해서 범인을 찾고, 그 범인이 어떤 종류의 I/O(순차/랜덤)를 하는지 패턴을 파악한 뒤, 만약 패턴 자체가 비효율적이라면 애플리케이션/DB 쿼리 레벨의 최적화로 돌아가시는 것을 가장 추천드립니다.
이 정도 깊이로 파고드시면 분명 좋은 답을 찾으실 수 있을 겁니다.
즐거운 모니터링 되시길 바랍니다!