[IT-정보] mkdir 성능 분석으로 서버 병목 잡기 – 디렉터리 생성 데이터로 부하 원인 파악하기

디렉터리 생성이 느려진 순간, 서버의 비명이 들리나요?

한밤중에 서버 모니터링 알람이 울려 급하게 터미널에 접속했어요. 평소라면 0.01초 만에 끝나야 할 mkdir 명령어가 수 초 동안 응답하지 않고 멈춰 있어요. 단순한 명령 하나가 왜 시스템 전체의 I/O Wait를 치솟게 만들고 다른 서비스까지 지연시키는지 원인을 찾지 못하면 운영자는 공포에 빠지게 돼요.

이런 현상은 단순히 명령어가 느린 것이 아니라, 파일시스템의 메타데이터 업데이트 과정에서 병목이 발생했음을 의미해요. 디렉터리를 생성하는 행위는 디스크에 데이터를 쓰는 것보다 훨씬 복잡한 과정을 거쳐요. 새로운 inode를 할당하고, 디렉터리 엔트리를 생성하며, 저널링 시스템에 기록을 남겨야 하거든요.

특히 대규모 분산 파일시스템이나 네트워크 기반의 NFS 환경을 운영한다면, 이 문제는 단순한 지연을 넘어 전체 클러스터의 가용성을 위협하는 치명적인 요소가 돼요. 오늘 이 글에서는 단순한 사용법을 넘어, 실제 성능 저하가 발생했을 때 어떤 지표를 보고 어떻게 대응해야 하는지 인프라 엔지니어의 관점에서 깊이 있게 다뤄볼게요.

이 글을 읽고 나면 다음과 같은 능력을 갖추게 돼요.

  • mkdir 실행 시 발생하는 시스템 콜의 흐름 이해
  • I/O Wait 급증 시 파일시스템과 디스크 간의 상관관계 분석
  • CPU와 메모리 지표를 통한 메타데이터 부하 판단
  • 병목 현상 발생 시 즉각적인 조치 방법 습득

성능 분석을 시작하기 전 반드시 체크해야 할 기본 지표

본격적인 분석에 들어가기 전에 현재 서버의 상태를 객관적으로 정의해야 해요. 무작정 명령어를 반복 실행하며 테스트하는 것은 오히려 시스템에 더 큰 부하를 줄 수 있어요. 먼저 분석의 기준점이 될 정상 상태의 지표를 확보하는 것이 첫 번째 순서예요.

가장 먼저 확인해야 할 것은 현재 사용 중인 파일시스템의 종류와 마운트 옵션이에요. 파일시스템마다 메타데이터를 관리하는 방식이 완전히 다르기 때문이에요. 예를 들어, Ext4와 XFS는 저널링(Journaling) 방식과 할당 알고리즘에서 큰 차이를 보여요. 또한, 네트워크 파일시스템인 NFS를 사용 중이라면 네트워크 레이턴시가 성능의 핵심 변수가 돼요.

💡 알아두기
mkdir 명령어는 단순한 파일 생성이 아니라, 커널의 VFS(Virtual File System) 계층을 거쳐 실제 물리 디스크의 메타데이터 영역을 수정하는 무거운 작업이에요.

다음은 성능 분석을 위해 엔지니어가 준비하고 비교해야 할 기준표예요.

체크 항목핵심 고려 사항영향도
파일시스템 유형Ext4, XFS, ZFS, NFS 등매우 높음
디스크 물리 특성SSD(NVMe) vs HDD vs Cloud EBS높음
Inode 사용량전체 Inode 대비 현재 할당량매우 높음
커널 버전파일시스템 드라이버 최적화 수준중간

단순히 명령어를 실행하는 것을 넘어, 파일시스템의 메타데이터 구조를 이해하는 것이 중요해요. 디렉터리를 만들 때 커널은 기존 디렉터리 파일 내부에 새로운 항목을 추가해야 하는데, 이때 기존 항목이 너무 많으면 검색(Lookup) 시간이 길어지고, 새로운 블록을 할당하는 과정에서 디스크 쓰기 부하가 발생하게 돼요. 이러한 사전 지식 없이 성능 테스트를 진행하면 결과 데이터의 왜곡을 초래할 수 있어요.

mkdir 성능 병목을 찾아내는 5단계 정밀 분석 프로세스

병목 구간을 정확히 특정하기 위해서는 현상 파악부터 부하 테스트까지 체계적인 접근이 필요해요. 추측에 의존하지 말고, 데이터로 증명하는 단계를 밟아야 해요.

STEP 1. 시스템 전반의 지표 관찰하기

가장 먼저 해야 할 일은 전체적인 시스템 리소스 상태를 확인하는 것이에요. `top`이나 `htop` 명령어를 통해 CPU 사용량 중 `wa` (I/O Wait) 비율이 얼마나 높은지 살펴보세요. 만약 `wa` 수치가 비정상적으로 높다면, 이는 CPU가 연산을 하는 것이 아니라 디스크의 응답을 기다리며 멍하니 서 있는 상태임을 의미해요.

또한 `iostat -xz 1` 명령어를 사용하여 특정 디스크 장치의 `%util` (사용률)과 `await` (평균 대기 시간)를 확인해야 해요. 디렉터리 생성 시 `await`가 수백 밀리초(ms) 단위로 튄다면, 파일시스템의 메타데이터 기록 작업이 디스크의 물리적 한계에 부딪혔을 가능성이 매우 커요. 이때는 디스크 성능 자체의 문제인지, 아니면 특정 프로세스가 I/O를 독점하고 있는지를 구분해야 해요.

STEP 2. 시스템 콜 레벨의 상세 추적

명령어가 왜 느린지 알려면 커널이 수행하는 실제 동작을 들여다봐야 해요. 이때 유용한 도구가 바로 strace예요. `strace -c mkdir test_dir` 명령어를 사용하면, `mkdir` 명령어가 실행되는 동안 어떤 시스템 콜이 몇 번 호출되었고, 각 호출에 시간이 얼마나 걸렸는지 통계를 보여줘요.

만약 `mkdir()` 자체의 시간은 짧은데, 그 과정에서 호출되는 `open()`, `write()`, 또는 `getdents()`와 같은 함수에서 시간이 오래 걸린다면 이는 디렉터리 내의 엔트리를 관리하거나 메타데이터를 업데이트하는 과정에서 병목이 발생하고 있다는 강력한 증거예요. 특히 대규모 디렉터리 구조 내에서 상위 디렉터리의 검색 속도가 느려지는 현상을 포착할 수 있어요.

STEP 3. 파일시스템 메타데이터 부하 분석

디렉터리 생성은 파일 데이터 자체보다는 Inode와 Dentry(Directory Entry)에 막대한 영향을 미쳐요. 하나의 디렉터리에 수만 개의 파일이나 하위 디렉터리가 모여 있다면, 새로운 항목을 추가할 때 커널은 적절한 위치를 찾기 위해 매우 긴 탐색 과정을 거쳐야 해요.

이 단계에서는 `df -i` 명령어를 통해 Inode 사용률을 반드시 체크해야 해요. Inode가 거의 고갈된 상태라면, 커널은 새로운 Inode를 할당하기 위해 빈 공간을 찾는 과정에서 극심한 성능 저하를 겪게 돼요. 또한, 파일시스템의 저널링(Journaling)이 너무 빈번하게 일어나고 있지는 않은지, 저널 영역의 크기가 너무 작아 병목을 유발하는지도 함께 검토해야 해요.

STEP 4. I/O 패턴 및 디스크 계층 분석

메타데이터 부하가 확인되었다면, 이제 이것이 실제 디스크 쓰기로 어떻게 이어지는지 확인해야 해요. `iotop`을 실행하여 `mkdir` 명령어가 생성하는 프로세스가 실제 디스크 쓰기(Write)를 얼마나 유발하는지, 그리고 해당 쓰기가 순차적(Sequential)인지 무작위(Random)인지 파악하세요. 메타데이터 작업은 성격상 매우 무작위적인 쓰기 패턴을 보이는 경우가 많으며, 이는 HDD 환경에서는 치명적이고 SSD 환경에서도 컨트롤러에 부하를 줄 수 있어요.

만약 클라우드 환경(AWS EBS 등)을 사용 중이라면, IOPS(초당 입출력 횟수) 한계에 도달했는지도 확인해야 해요. Burst Balance가 바닥나서 성능 제한(Throttling)이 걸린 상태라면, 아무리 명령어를 최적화해도 성능은 나아지지 않아요.

STEP 5. 통제된 환경에서의 스트레스 테스트

마지막으로, 실제 운영 환경과 유사한 시나리오를 만들어 성능을 정량화해야 해요. 단순히 `mkdir`을 한 번 하는 것이 아니라, 쉘 스크립트를 작성하여 수천 개의 디렉터리를 계층적으로 생성하는 테스트를 진행하세요.

💡 알아두기
테스트 시에는 반드시 운영 중인 서비스에 영향을 주지 않는 별도의 테스트 디렉터리나 디스크 파티션을 활용해야 해요.

다음은 테스트 시나리오 예시예요.

  • 시나리오 A (단일 계층): 하나의 디렉터리 안에 10,000개의 하위 디렉터리를 생성할 때의 시간 측정
  • 시나리오 B (심층 계층): 10단계 깊이의 트리 구조를 만들며 생성할 때의 지연 시간 측정
  • 시나리오 C (병렬 생성): 여러 개의 프로세스가 동시에 `mkdir`을 실행할 때의 I/O 경합 측정

이러한 데이터를 기반으로 하면,

자주 하는 실수와 해결법 및 FAQ

자주 하는 실수와 해결법

현장에서 엔지니어들이 흔히 범하는 실수들을 정리했어요. 문제를 마주했을 때 빠르게 대조해 보세요.

  • 실수: 디스크 용량이 충분하므로 성능 문제가 없을 것이라고 단정함
    왜 발생하는가: 용량(Capacity)과 Inode(Metadata 공간)는 별개의 개념이기 때문이에요.
    → ✅ 해결법: 반드시 `df -i` 명령어로 Inode 사용률을 함께 확인하세요.
  • 실수: SSD로 교체하면 모든 I/O 문제가 해결될 것이라 믿음
    왜 발생하는가: 파일시스템 설계나 커널의 잠금(Lock) 경합 문제는 하드웨어 성능만으로 해결되지 않아요.
    → ✅ 해결법: 파일시스템의 마운트 옵션(예: noatime)을 조정하거나 디렉터리 구조를 분산하세요.
  • 실수: 네트워크 지연을 고려하지 않고 로컬 디스크 문제로만 치부함
    왜 발생하는가: NFS나 CIFS 같은 네트워크 파일시스템은 네트워크 패킷 왕복 시간이 명령 수행 시간의 대부분을 차지해요.
    → ✅ 해결법: `ping`이나 `nfsstat`을 통해 네트워크 레이턴시를 먼저 측정하세요.
  • 실수: 한 디렉터리에 수만 개의 파일을 몰아넣는 설계를 방치함
    왜 발생하는가: 파일 개수가 많아질수록 디렉터리 엔트리 탐색(Lookup) 비용이 기하급수적으로 늘어나요.
    → ✅ 해결법: 날짜나 해시값을 기준으로 디렉터리를 계층화(Sharding)하여 관리하세요.
  • 실수: 저널링 부하를 무시하고 고속 쓰기 작업만 수행함
    왜 발생하는가: 메타데이터의 무결성을 지키기 위한 저널링 쓰기가 쓰기 성능을 제한할 수 있어요.
    → ✅ 해ผล법: 메타데이터 업데이트가 잦은 작업이라면 저널링 크기를 키우거나 성능 최적화된 파일시스템을 선택하세요.

자주 묻는 질문

Q. mkdir 명령어가 왜 CPU 사용량을 높이나요?

디렉터리 생성은 디스크 쓰기뿐만 아니라, 커널이 새로운 inode를 할당하고 비어 있는 디렉터리 엔트리 공간을 계산하며 메모리 상의 캐시(Dentry Cache)를 업데이트하는 CPU 연산 과정을 포함하기 때문이에요.

Q. NFS 환경에서 mkdir이 유독 느린 이유는 무엇인가요?

NFS는 디렉터리 생성 요청을 서버로 보내고, 서버가 파일시스템에 기록한 뒤, 성공했다는 응답을 다시 클라이언트로 보내는 과정을 거쳐요. 이 과정에서 발생하는 네트워크 지연(Latency)과 서버 측의 파일 잠금(File Locking) 메커니즘이 결합되어 속도가 느려질 수 있어요.

Q. 디렉터리 깊이(Depth)가 성능에 미치는 영향은 어느 정도인가요?

깊이가 깊어질수록 각 단계의 디렉터리를 통과할 때마다 새로운 경로 탐색(Path Lookup)이 필요해요. 이는 시스템 콜의 연속적인 발생과 캐시 미스를 유발하여, 평면적인 구조보다 훨씬 많은 오버헤드를 발생시켜요.

Q. 성능을 높이기 위해 noatime 옵션을 쓰면 도움이 되나요?

네, 도움이 돼요. 기본적으로 리눅스는 파일을 읽기만 해도 ‘마지막 접근 시간(atime)’을 업데이트하기 위해 쓰기 작업을 수행해요. `noatime` 옵션을 사용하면 이러한 불필요한 메타데이터 업데이트를 막아 성능을 개선할 수 있어요.

Q. Inode 고갈 문제를 예방하는 가장 좋은 방법은 무엇인가요?

파일을 생성할 때 무분별하게 작은 파일을 수없이 만드는 것을 지양해야 해요. 가급적 큰 단위로 묶어서 관리하거나, Inode 할당량이 넉넉한 파일시스템(예: XFS)을 선택하는 것이 유리해요.

안정적인 서버 운영을 위한 성능 관리 루틴

디렉터리 생성 성능 문제는 단순히 명령어 하나가 느려지는 문제가 아니라, 시스템의 메타데이터 관리 체계가 한계에 도달했음을 알리는 신호예요. 오늘 다룬 내용을 바탕으로 장애를 예방하기 위한 핵심 체크리스트를 정리해 드릴게요.

✅ 핵심 요약

  • 디렉터리 생성 지연 시 I/O Wait와 Inode 사용량을 최우선으로 확인하세요.
  • strace를 활용해 어떤 시스템 콜에서 지연이 발생하는지 데이터로 증명하세요.
  • 파일시스템별 메타데이터 관리 특성(Ext4 vs XFS)을 이해하고 환경에 맞게 선택하세요.
  • 대량의 파일을 관리할 때는 반드시 디렉터리 계층화(Sharding)를 적용하세요.
  • 네트워크 환경(NFS)이라면 디스크 성능보다 네트워크 레이턴시를 먼저 체크하세요.
  • noatime 옵션 등 마운트 최적화를 통해 불필요한 쓰기를 줄이세요.

지금 바로 실행할 수 있는 단계별 액션 플랜을 제안해요.

  • 오늘 할 일: 주요 데이터 디스크의 `df -i` 명령어를 실행해 Inode 사용률이 80%를 넘지 않는지 확인하세요.
  • 이번 주 할 일: `iostat`과 `top`을 활용해 서비스 피크 시간대의 I/O Wait 패턴을 기록해 두세요.
  • 실행 직전 할 일: 디렉터리 구조가 너무 깊거나 한 곳에 몰려 있다면, 애플리케이션의 저장 경로 설계 방안을 검토하세요.

평상시 지표를 미리 기록해 두어야 장애 발생 시 비교할 기준점이 생겨요. 지금 바로 여러분의 서버 지표를 기록하기 시작하세요!

관련된 더 자세한 정보가 필요하다면 리눅스 파일관리 명령어 모음 글을 참고해 보세요.

댓글 남기기