사전 지식: 리눅스는 파일을 어떻게 관리할까?
이 현상을 이해하려면 리눅스 파일 시스템의 두 가지 핵심 개념인 아이노드(Inode)와 디렉토리 엔트리(Dentry)를 알아야 합니다.
- 디렉토리 엔트리 (Directory entry): 이름과 번호표의 짝꿍 리눅스에서는 디렉토리(폴더)도 결국 하나의 특수한 파일입니다. 달리말하면, 파일시스템이 해석하는 구조화된 엔트리들의 집합입니다. 디렉토리라는 특수한 파일 안에는 그 폴더 안에 있는 파일들의 이름'과 그 파일의 '아이노드 번호'가 1:1로 매핑된 목록(Dentry)이 텍스트처럼 쭉 적혀 있습니다. 이것도 디스크 내에 저장되어있습니다. 주의해야할 것은 dentry라는 개념이 있는데, 이건 메모리에 있는 것입니다.
- 아이노드 (Inode): 파일의 주민등록증. 파일의 메타데이터를 담은 것. 디렉토리는 본질적으로 파일이름-inode 번호를 매핑을 담은 특수한 파일입니다. 즉, 리눅스는 파일의 이름과 파일의 실제 데이터를 분리해서 저장합니다. 아이노드는 파일의 메타데이터(크기, 권한, 소유자, 생성 시간 등)와 실제 데이터가 하드 디스크의 어디에 저장되어 있는지(데이터 블록 주소)를 담고 있는 고유한 번호표입니다.
아래의 그림은 blocks(데이터블록, 실제로 데이터가 저장되는 칸)과 그 접근방법에 대한 그림입니다. 만일 "ls"으로 디렉토리 내에 파일 목록을 출력하게 커멘트를 날리면, 다음의 과정이 일어납니다.
- 운영체제는 현재 머물고 있는 디렉토리 자체의 inode를 찾습니다.
- 이 inode를 통해 현재 디렉토리의 내용(데이터)이 디스크의 어느 block에 저장되어 있는지 위치를 알아냅니다.
- inode을 읽어서, directory entry들을 읽어옵니다.
- 필요하면 각 항목의 inode를 추가 조회합니다. (ls -al 하는경우). 운영체제는 해당 디스크 블록으로 달려가서 디렉토리의 내용을 쭉 읽어옵니다. (이때 내부적으로 getdents라는 시스템 콜이 사용됩니다.) 여기서 읽어오는 내용이 바로 앞서 살펴본 dentry (파일 이름 + Inode 번호의 목록)입니다. 결과물: "a.txt는 101번, b.jpg는 102번, sub_folder는 103번..." 이런 식의 단순한 텍스트 리스트를 확보합니다.

위 처럼, 디렉토리 엔트리(directory entry)내에 inode위치가 있고 ionode에 주소랑 파일내용등에 대한 메타데이터를 저장하고있습니다.
한 폴더 내에 파일이 많으면 왜 느려지나? => 디렉토리 엔트리의 내용을 다 읽어야하기 때문
사람들은 보통 “파일이 많으면 디스크 용량이 커서 느리다”고 생각하지만, 실제 병목은 파일 내용보다 메타데이터 처리인 경우가 많습니다. ls를 실행하면 운영체제는 현재 디렉토리의 데이터를 읽어서 그 안에 들어 있는 엔트리들을 하나씩 가져와야 합니다. 이런 디렉토리 읽기는 readdir() 계열 동작으로 이루어지며, 결국 파일이 10개면 10개를, 100만 개면 100만 개를 훑어야 합니다. 즉, 파일 수가 많을수록 ls는 단순히 “이름 목록을 전부 스캔하는 비용” 때문에 느려집니다.
여기서 중요한 점은 dentry cache가 있어도 ls의 전체 비용을 없애주지는 못한다는 것입니다. dentry cache는 /home/user/data 같은 경로를 다시 찾을 때는 매우 유리하지만, ls는 특정 파일 하나를 찾는 작업이 아니라 디렉토리 안 전체 목록을 나열하는 작업이기 때문입니다. 즉, “이 폴더가 어디 있지?”는 캐시로 빨라질 수 있어도, “이 폴더 안에 뭐가 다 있지?”는 결국 많이 읽어야 합니다.
특히 ls -l은 왜 더 느립니다.
plain ls는 주로 이름 목록을 보여주는 쪽이지만, ls -l은 권한, 소유자, 파일 크기, 시간 정보까지 보여줘야 합니다. 이 정보들은 디렉토리 엔트리만으로는 충분하지 않고, 각 파일의 inode 메타데이터를 추가로 확인해야 합니다. 이때 stat() 계열 조회가 들어가므로, 파일이 많을수록 ls -l은 plain ls보다 훨씬 더 무거워집니다.
실무에서 어떻게 해결하면 좋을까?
1. 가장 중요한 해결책: 디렉터리를 쪼개기
가장 권장되는 방법입니다.
예를 들면:
- 날짜 기반: YYYY/MM/DD/
- 해시 기반: ab/cd/<filename>
- 사용자/프로젝트 기반: user_id/project_id/
이렇게 하면 한 디렉터리의 엔트리 수를 낮춰서 listing, stat, 정렬, 탐색기 로딩 비용을 줄일 수 있습니다.
2. metadata-heavy 명령을 피하라
큰 디렉터리에서는 ls -l보다 ls가 낫고, 정렬까지 피하려면 ls -U도 도움이 됩니다. GUI 탐색기보다 CLI가 유리할 때도 많습니다. Oracle과 Ceph 문서가 설명하듯, 상세 목록과 반복적인 metadata 조회가 큰 비용입니다.
3. 셸 프롬프트/자동완성을 가볍게 하라
cd가 느리게 느껴지면 .bashrc, .zshrc, starship, powerlevel10k, git prompt 등을 먼저 의심하는 게 좋습니다. 특히 큰 저장소나 파일 많은 디렉터리에서 git 상태를 동기적으로 읽는 프롬프트는 체감 성능을 크게 떨어뜨립니다. 이건 파일시스템 자체 문제라기보다 도구 계층 문제입니다.
'Data science' 카테고리의 다른 글
| SLURM 단위 (Job, Task) 이해 (0) | 2025.11.13 |
|---|---|
| Airflow 사용법 및 기본 예제 (0) | 2025.03.10 |
| GitHub Actions 의존성 캐싱하기 (0) | 2025.01.17 |
| [5분 안에 이해하는] 프롬프트 엔지니어링 핵심기법: Few shot ,CoT, SC, ReACT, RAG (0) | 2024.04.15 |
| 구글드라이브 파일 wget 사용하기 (0) | 2022.11.11 |