디스크 공간 할당과 파일 시스템 선택 기준
Extent, 지연 할당, Copy-on-Write를 중심으로 ext4·XFS·Btrfs·ZFS·APFS의 공간 할당 방식과 워크로드별 선택·튜닝 방법을 정리한다.
2026-08-14 · 최초 발행 2026-01-02
블록 하나씩 기록하던 방식에서 Extent로
파일 하나에 속한 블록 주소를 inode 포인터로 각각 기록하면 파일이 커질수록 메타데이터와 간접 포인터 부담이 커진다. 현대 파일 시스템은 이 문제를 피하기 위해 연속된 블록 구간을 Extent로 묶는다. Extent는 시작 블록과 길이의 쌍으로 표현되며, 큰 파일의 메타데이터를 줄이고 순차 접근에 유리한 배치를 만들 수 있다.
ext4의 Extent Tree는 다음처럼 여러 연속 구간을 관리한다.
Extent Header
├─ Extent 1: (Block 1000, Length 100)
├─ Extent 2: (Block 2000, Length 200)
└─ Extent 3: (Block 5000, Length 500)
연속 블록을 확보하면 단편화가 줄고, 대용량 파일을 다룰 때 메타데이터도 효율적으로 유지된다.
쓰기 요청 직후 물리 블록을 정하지 않는 지연 할당도 같은 목적에 닿아 있다. 데이터는 먼저 페이지 캐시에 머무르고, 플러시 시점에 파일 시스템이 더 적절한 위치를 골라 큰 Extent로 할당한다. ext4, XFS, Btrfs가 지원하는 방식으로, 단편화와 메타데이터 갱신을 줄이며 순차 쓰기 성능을 높일 수 있다.
파일 시스템마다 다른 할당 방식과 쓰임새
ext4는 Linux의 표준 파일 시스템으로 Extent 기반 할당과 저널링을 제공한다. 최대 파일 크기는 16TB, 최대 볼륨 크기는 1EB다. Multi-Block Allocator는 여러 블록을 한 번에 할당하면서 블록 그룹 안의 연속 공간을 찾고, fallocate()를 이용한 사전 할당은 데이터베이스 파일처럼 공간을 미리 확보할 때 쓸 수 있다. 범용 Linux 서버나 부팅 파티션처럼 안정성과 성능의 균형이 필요한 환경에 맞는다.
XFS는 대용량 파일과 디렉터리에 초점을 둔 고성능 저널링 파일 시스템이다. 최대 파일 크기는 8EB이며, Extent 기반 B+ Tree를 사용한다. 볼륨을 Allocation Group으로 나누어 병렬 I/O와 할당을 처리하고, 순차 쓰기가 감지되면 추가 공간을 예약했다가 사용하지 않은 부분은 해제한다. 마운트 상태에서 xfs_fsr로 조각 모음도 가능하다. 대용량 파일 서버, Oracle·PostgreSQL 데이터베이스, 영상 편집과 스트리밍, 고성능 컴퓨팅이 주된 대상이다.
Btrfs는 CoW를 중심에 둔 Linux 파일 시스템이다. 데이터를 수정할 때 기존 위치를 덮어쓰지 않고 새 위치에 기록하므로 원본 보존과 스냅샷 생성에 유리하다. 데이터와 메타데이터는 별도 청크로 관리하고, 동적 할당과 RAID를 지원한다. zlib, lzo, zstd를 통한 실시간 압축으로 공간 사용량과 I/O를 줄일 수 있다. 스냅샷이 잦은 가상화 환경이나 데이터 무결성, 자가 치유가 필요한 곳에 적합하다.
스토리지 풀과 공간 공유를 다루는 ZFS·APFS
ZFS는 볼륨 관리자와 파일 시스템을 통합하고, CoW와 엔드투엔드 데이터 무결성, 스냅샷·클론 기능을 제공한다. zpool은 물리 디스크를 하나의 풀로 통합하며 동적 스트라이핑과 RAID-Z를 지원한다. 레코드 기반 할당은 512B ~ 1MB의 가변 블록 크기를 사용하고, 압축 뒤 실제 크기만큼 공간을 잡는다. ARC는 LRU와 LFU를 결합한 메모리 캐시다.
중복 제거는 동일 블록을 한 번만 저장하고 해시 테이블로 관리하는 기능이며 백업 서버에 유용하다. ZFS는 모든 데이터에 체크섬을 적용하고 RAID 환경에서 Self-Healing을 제공해 사일런트 데이터 손상을 막는다. NAS, 스토리지 서버, 백업 시스템, 데이터 아카이브와 FreeBSD·Linux의 OpenZFS 환경이 주요 활용처다.
APFS는 2017~부터 macOS와 iOS의 표준 파일 시스템으로, Flash와 SSD에 맞춰 설계됐다. CoW, 스냅샷, 클론을 제공하며 여러 볼륨이 하나의 풀을 공유하는 Space Sharing으로 파티션 크기를 조절하지 않고 공간을 유연하게 쓸 수 있다. Sparse File은 실제로 사용한 공간만 할당하고 빈 영역은 0바이트로 처리한다. 파일 클론은 복사 시 CoW를 사용하므로 즉시 복사와 공간 절약이 가능하며 Time Machine 백업에도 적합하다.
벤치마크는 워크로드를 닮아야 한다
파일 시스템을 비교할 때는 순차 읽기·쓰기의 처리량, 랜덤 읽기·쓰기의 IOPS, 그리고 ms·μs 단위 지연 시간을 함께 본다. 지연 시간은 P50, P95, P99 퍼센타일로 확인할 수 있으며 데이터베이스나 실시간 애플리케이션에서 특히 중요하다.
fio는 순차·랜덤과 읽기·쓰기를 조합해 실제 애플리케이션 패턴을 재현하는 도구다.
# 순차 쓰기 테스트
fio --name=seq-write --rw=write --bs=1M --size=10G --numjobs=1 \
--directory=/mnt/test --ioengine=libaio --direct=1
# 랜덤 읽기 IOPS 테스트
fio --name=rand-read --rw=randread --bs=4K --size=1G --numjobs=16 \
--directory=/mnt/test --ioengine=libaio --direct=1 --iodepth=64
iozone은 파일 크기와 레코드 크기 조합을 바꿔 파일 시스템을 측정하고 그래프를 출력한다. sysbench는 fileio 모드와 OLTP 시뮬레이션으로 데이터베이스 워크로드를 다룬다.
NVMe SSD에서 측정한 순차 쓰기 예시는 다음과 같다.
| 파일 시스템 | 1 Thread | 4 Threads | 16 Threads |
|---|---|---|---|
| ext4 | 2800 | 3200 | 3400 |
| XFS | 3100 | 3500 | 3600 |
| Btrfs | 2600 | 3000 | 3200 |
| ZFS | 2400 | 2900 | 3100 |
랜덤 4K 읽기 IOPS 예시도 함께 봐야 한다.
| 파일 시스템 | QD=1 | QD=32 | QD=128 |
|---|---|---|---|
| ext4 | 12000 | 95000 | 180000 |
| XFS | 13000 | 100000 | 190000 |
| Btrfs | 11000 | 85000 | 160000 |
| ZFS (ARC) | 14000 | 120000 | 200000 |
이 예시에서는 XFS가 순차 처리량에서, ARC를 사용하는 ZFS가 랜덤 읽기에서 우수했다. Btrfs는 CoW 오버헤드 때문에 다소 낮았고, ext4는 균형 잡힌 성능을 보였다.
마운트 옵션과 생성 파라미터를 조정할 때
ext4에서는 성능 우선과 안정성 우선의 마운트 옵션이 다르다.
# 성능 우선
mount -o noatime,nodiratime,data=writeback /dev/sda1 /mnt
# 안정성 우선
mount -o data=journal,barrier=1 /dev/sda1 /mnt
noatime은 접근 시간 갱신을 생략한다. data=writeback은 메타데이터만 저널링하므로 빠르지만 덜 안전하고, data=journal은 데이터까지 저널링해 느리지만 안전하다. commit=60은 저널 커밋 간격을 초 단위로 지정한다. 파일 시스템을 만들 때 inode 관련 값도 조절할 수 있다.
# 파일 시스템 생성 시
mkfs.ext4 -i 16384 -I 256 /dev/sda1
# -i: bytes-per-inode (더 많은 inode)
# -I: inode 크기 (extended attributes용)
XFS는 Allocation Group 수와 로그 버퍼 설정으로 병렬성과 쓰기 경로를 조정한다.
# 큰 AG로 생성 (병렬성 향상)
mkfs.xfs -d agcount=64 /dev/sda1
mount -o noatime,nodiratime,logbsize=256k,logbufs=8 /dev/sda1 /mnt
logbsize는 로그 버퍼 크기, logbufs는 로그 버퍼 개수다. 대용량 쓰기에서는 로그 성능에 영향을 준다. 실시간 데이터를 별도 고속 장치에 둘 수도 있다.
mkfs.xfs -r rtdev=/dev/nvme0n1,size=100G /dev/sda1
mount -o rtdev=/dev/nvme0n1 /dev/sda1 /mnt
Btrfs의 압축 방식과 CoW 동작도 워크로드에 따라 선택한다.
mount -o compress=zstd:3 /dev/sda1 /mnt
# zstd: 빠른 압축, 낮은 CPU
# lzo: 더 빠름, 낮은 압축률
# zlib: 느림, 높은 압축률
chattr +C /var/lib/mysql
# Copy-on-Write 비활성화
# 스냅샷 불가하지만 성능 향상
mount -o autodefrag /dev/sda1 /mnt
ZFS는 ARC 크기, 레코드 크기, 압축, 중복 제거를 조정 대상으로 둔다.
# /etc/modprobe.d/zfs.conf
options zfs zfs_arc_max=17179869184 # 16GB
zfs set recordsize=128K tank/database
# 데이터베이스: 8K-16K
# 대용량 파일: 128K-1M
zfs set compression=lz4 tank/data
# lz4: 빠르고 효율적
# gzip-9: 높은 압축률, 느림
zfs set dedup=on tank/backup
# RAM 많이 사용 (1TB당 5GB RAM)
# 백업 서버에만 권장
워크로드가 선택을 결정하는 장면
데이터베이스 서버는 4K-16K의 작은 블록으로 랜덤 읽기·쓰기를 반복하고 fsync() 호출도 잦다. 낮은 지연 시간이 중요할 때 XFS는 Oracle과 PostgreSQL에서 공식 권장되며, 큰 파일과 Direct I/O 성능, Online 확장이 강점이다. 배터리 백업 RAID 컨트롤러가 있는 경우에는 다음 설정을 사용할 수 있다.
mkfs.xfs -d agcount=64 /dev/sda1
mount -o noatime,nodiratime,nobarrier /dev/sda1 /var/lib/pgsql
# 배터리 백업 RAID 컨트롤러 있을 때 nobarrier
ext4는 안정성과 지연 할당을 제공하는 대안이며 data=ordered가 기본값이다.
VM 이미지는 스냅샷, 클론, 공간 효율, Thin Provisioning이 핵심이다. Btrfs는 CoW와 서브볼륨을 이용해 VM별 관리와 스냅샷을 처리할 수 있다.
mkfs.btrfs /dev/sda1
mount -o compress=zstd,autodefrag /dev/sda1 /var/lib/libvirt
# VM 이미지용 서브볼륨
btrfs subvolume create /var/lib/libvirt/images
# 스냅샷
btrfs subvolume snapshot /var/lib/libvirt/images \
/var/lib/libvirt/snapshots/vm-backup-$(date +%F)
ZFS도 zvol, 스냅샷, 클론, 데이터 무결성을 제공하므로 대안이 된다.
대용량 파일을 여러 스트림으로 읽고 쓰는 멀티미디어 서버에서는 XFS의 Extent 기반 할당과 높은 순차 처리량이 맞는다.
mkfs.xfs -d agcount=32 -l size=256m /dev/sda1
mount -o noatime,logbsize=256k /dev/sda1 /media/videos
NAS와 백업 서버는 무결성, 중복 제거, 압축, RAID 관리가 중심이므로 ZFS의 통합 볼륨 관리와 체크섬, 스냅샷 기능을 활용할 수 있다.
# RAID-Z2 풀 생성 (이중 패리티)
zpool create tank raidz2 sda sdb sdc sdd sde sdf
# 데이터셋 생성
zfs create tank/backup
zfs set compression=lz4 tank/backup
zfs set dedup=on tank/backup # RAM 충분 시
# 스냅샷
zfs snapshot tank/backup@daily-$(date +%F)
모바일과 임베디드 환경은 Flash·SSD, 전력 효율, 공간 효율, 빠른 부팅이 중요하다. F2FS는 SSD와 eMMC에 최적화된 Log-structured 파일 시스템으로 TRIM을 지원하며 Android에서 권장된다. Apple 기기에서는 SSD 최적화, 클론·스냅샷, 내장 암호화와 공간 효율을 갖춘 APFS가 대상이다.
이전과 운영에서 확인할 지점
파일 시스템 전환은 rsync나 archive 모드의 cp로 데이터를 복사하는 방식으로 진행할 수 있다.
# rsync로 안전한 복사
rsync -avhP --delete /old-fs/ /new-fs/
# cp with archive mode
cp -a /old-fs/* /new-fs/
LVM 환경에서는 물리 볼륨 이동과 논리 볼륨 재생성을 이용한 온라인 전환도 가능하다.
# LVM에서 파일 시스템 전환
pvmove /dev/sda1 /dev/sdb1 # 데이터 이동
lvremove /dev/vg0/old-lv
lvcreate -L 100G -n new-lv vg0
mkfs.xfs /dev/vg0/new-lv
운영 중에는 iostat으로 디스크 사용률, 평균 응답 시간, 서비스 타임을 확인한다.
iostat -x 1
# %util: 디스크 사용률
# await: 평균 응답 시간
# svctm: 서비스 타임
I/O가 발생하는 프로세스만 보려면 iotop을 사용한다.
iotop -o # I/O 발생 프로세스만
파일 시스템별 진단 명령은 다음과 같다.
# ext4
tune2fs -l /dev/sda1 # 슈퍼블록 정보
dumpe2fs /dev/sda1
# XFS
xfs_info /mnt
xfs_db -r /dev/sda1
# Btrfs
btrfs filesystem show
btrfs device stats /mnt
# ZFS
zpool status
zfs list -o space
디스크가 가득 찼다면 용량, 큰 파일, inode 사용량을 차례로 확인하고 ext4 예약 블록도 조정 대상이 된다.
# 용량 확인
df -h
# 큰 파일 찾기
du -sh /* | sort -rh | head -10
# inode 부족 확인
df -i
# ext4 예약 블록 줄이기
tune2fs -m 1 /dev/sda1 # 5% → 1%
단편화는 파일 시스템별 도구로 점검하고 해소한다.
# ext4 단편화 확인
e4defrag -c /mnt
# ext4 온라인 디프래그
e4defrag /mnt
# XFS 디프래그
xfs_fsr /mnt
# Btrfs 디프래그
btrfs filesystem defragment -r /mnt
성능이 떨어지면 free -h의 buff/cache, cat /sys/block/sda/queue/scheduler의 I/O 스케줄러, 마운트 옵션을 검토한다. SSD는 noop 또는 none, HDD는 deadline 또는 cfq를 사용하며, 필요하면 fsck, xfs_repair, btrfs check로 파일 시스템을 확인한다.