LLM WikiAccess-protected knowledge portal
← 스터디 홈
1편 · 약 28분

스토리지 시스템 기초: 블록·파일·오브젝트 스토리지와 I/O 스택

왜 DBA는 스토리지를 깊이 알아야 하는가

데이터베이스 성능 문제의 상당수는 코드가 아니라 스토리지에서 온다. 쿼리 최적화를 아무리 열심히 해도, 디스크 I/O 병목 앞에서는 무력하다. InnoDB 버퍼 풀이 충분히 크다고 해도, 데이터가 디스크에서 올라오는 순간의 레이턴시는 피할 수 없다.

DBA와 데이터 플랫폼 엔지니어가 스토리지를 알아야 하는 이유는 세 가지다. 첫째, 장애 진단이다. I/O 포화, 디스크 오류, 파일시스템 손상은 데이터베이스 장애로 직결된다. 둘째, 용량 계획이다. 데이터 증가 속도와 스토리지 특성을 이해해야 적절한 시점에 확장 결정을 내릴 수 있다. 셋째, 성능 튜닝이다. 어떤 스토리지 타입을 선택하고, I/O 스케줄러를 어떻게 설정하느냐에 따라 같은 쿼리의 응답시간이 크게 달라진다.


세 가지 스토리지 패러다임

현대 인프라에서 스토리지는 세 가지 방식으로 제공된다. 각각의 접근 모델, 강점, 약점을 명확히 구분하는 것이 설계의 출발점이다.

블록 스토리지 Block Storage 원시 블록 단위 접근 (512B / 4KB) • 인터페이스: iSCSI, FC, NVMe-oF • 파일시스템: 애플리케이션이 직접 포맷 • 레이턴시: 가장 낮음 (µs~ms) • 적합: DB, 가상머신 디스크, K8s PV • 비적합: 대용량 비정형 데이터 → RDS, EBS, Persistent Disk 파일 스토리지 File Storage (NAS) 디렉토리 / 파일 계층 구조 • 인터페이스: NFS, CIFS/SMB • 접근 모델: POSIX 경로 기반 • 레이턴시: 중간 (ms 범위) • 적합: 공유 로그, ML 데이터셋 • 비적합: 고 IOPS 랜덤 쓰기 DB → EFS, Cloud Filestore, NFS 오브젝트 스토리지 Object Storage key → value (평탄한 주소 공간) • 인터페이스: HTTP REST (S3 API) • 메타데이터: 사용자 정의 가능 • 레이턴시: 가장 높음 (ms~100ms) • 적합: Data Lake, 백업, 아카이브 • 비적합: 저레이턴시 트랜잭션 DB → S3, GCS, MinIO, Ceph
세 가지 스토리지 패러다임 비교

선택 기준 요약

2025년 이후 클라우드 환경의 기본 원칙은 다음과 같다.

  • 블록 스토리지: 데이터베이스, VM 디스크, Kubernetes PersistentVolume. 랜덤 I/O와 낮은 레이턴시가 필요한 모든 워크로드.
  • 파일 스토리지: 여러 서버가 동시에 접근해야 하는 공유 디렉토리. 진짜로 공유가 필요한 경우에만 사용.
  • 오브젝트 스토리지: 낮은 레이턴시가 필요 없는 모든 대용량 데이터. Data Lake, 백업, 아카이브, 정적 에셋.

새로운 흐름: 2024년 InfluxDB 3.0 이후 "Zero-Disk Architecture"가 주목받는다. 로컬 스토리지 없이 오브젝트 스토리지(S3)를 기본 영속성 레이어로 사용하는 설계로, InfluxDB, DuckDB, ClickHouse Cloud가 이 방향으로 가고 있다. 하지만 레이턴시 민감한 OLTP 데이터베이스에서는 여전히 로컬 블록 스토리지가 기본이다.


Linux I/O 스택의 구조

데이터베이스가 데이터를 읽고 쓸 때 실제로 무슨 일이 일어나는지 이해하려면 Linux I/O 스택을 알아야 한다. 스택은 위에서 아래로 다음과 같이 구성된다.

애플리케이션 / 데이터베이스 MySQL, PostgreSQL, ClickHouse … read() / write() / fsync() VFS (Virtual File System) 통일된 파일 인터페이스 추상화 — open/read/write/stat/fsync 페이지 캐시 (Page Cache) 커널 메모리의 디스크 블록 캐시 — cache hit 시 디스크 접근 없음 파일시스템 (ext4 / XFS / Btrfs) 디렉토리 구조, inode, 저널링 — 블록 주소로 변환 블록 레이어 (blk-mq) + I/O 스케줄러 I/O 요청 병합·정렬·큐잉 — none / mq-deadline / kyber Direct I/O(O_DIRECT)는 페이지 캐시를 바이패스하여 블록 레이어로 직접 진입 디바이스 드라이버 / 물리 장치 NVMe / SATA SSD / HDD — 실제 전기·자기 신호로 데이터 기록 Buffered I/O Direct I/O
Linux I/O 스택 레이어

핵심 레이어 설명

페이지 캐시: Linux 커널이 디스크 블록을 메모리에 캐싱하는 공간이다. MySQL InnoDB는 자체 버퍼 풀을 사용하므로 O_DIRECT로 페이지 캐시를 바이패스한다. PostgreSQL은 버퍼드 I/O를 사용하므로 공유 버퍼(shared_buffers) 위에 커널 페이지 캐시가 한 겹 더 있다.

O_DIRECT: open() 플래그. 페이지 캐시를 건너뛰고 블록 레이어로 직접 I/O를 보낸다. MySQL InnoDB의 기본 설정. 이중 캐싱을 방지하고 버퍼 풀 크기를 예측 가능하게 유지한다.

fsync(): 커널 버퍼에 남아 있는 더티 데이터를 디스크에 강제로 플러시한다. InnoDB의 innodb_flush_log_at_trx_commit=1은 커밋마다 fsync()를 호출한다. 가장 안전하지만 I/O 부하가 가장 크다.


저장 매체의 물리적 특성

HDD, SATA SSD, NVMe의 차이

특성HDDSATA SSDNVMe (PCIe 4.0)
읽기 IOPS100~20050,000~100,000500,000~1,000,000+
쓰기 IOPS100~20030,000~80,000200,000~700,000+
읽기 레이턴시3~10 ms50~100 µs20~70 µs
쓰기 레이턴시5~15 ms50~150 µs20~100 µs
순차 읽기 대역폭100~200 MB/s500~600 MB/s3,500~7,000 MB/s
랜덤 vs 순차 차이매우 큼 (헤드 이동)작음거의 없음

실무 참고: MongoDB 기준으로 NVMe는 동일 쿼리에서 SATA SSD 대비 레이턴시를 8.2 ms → 1.1 ms로 낮추는 사례가 보고되었다.

왜 랜덤 I/O가 중요한가

데이터베이스 워크로드는 대부분 랜덤 I/O다. B-Tree 인덱스 탐색, InnoDB 페이지 읽기, WAL 이외의 작업은 순차적으로 디스크를 읽지 않는다. HDD에서 랜덤 I/O가 느린 이유는 물리적 헤드 이동(seek time) 때문이다. SSD와 NVMe는 기계 장치가 없으므로 랜덤 I/O 페널티가 극적으로 줄어든다.


Linux I/O 스케줄러 설정

I/O 스케줄러는 디바이스 드라이버에 전달되기 전 I/O 요청을 어떻게 병합하고 정렬할지 결정한다. Linux 4.12 이후 blk-mq 프레임워크 기반으로 전환되었다.

none (또는 noop)
별도 정렬 없이 요청을 드라이버에 직접 전달. NVMe처럼 이미 자체 큐 최적화가 있는 장치에 적합.
권장 대상: NVMe SSD, 클라우드 인스턴스 스토리지 (AWS EBS, GCP PD 등)
echo none > /sys/block/nvme0n1/queue/scheduler
mq-deadline
요청에 데드라인을 부여하여 starvation을 방지하면서 요청 병합. 읽기에 쓰기보다 짧은 데드라인 부여.
권장 대상: SATA SSD, HDD가 남아 있는 환경, Oracle DB 공식 권고.
echo mq-deadline > /sys/block/sda/queue/scheduler
bfq (Budget Fair Queueing)
프로세스 단위 공정 큐잉. 멀티 테넌트 환경에서 특정 프로세스의 I/O 독점 방지에 유리.
권장 대상: 여러 프로세스가 디스크를 공유하는 데스크탑·컨테이너 환경.
데이터베이스 전용 서버에서는 일반적으로 none 또는 mq-deadline이 더 나은 성능.
스케줄러별 특성 비교

현재 스케줄러 확인:

cat /sys/block/nvme0n1/queue/scheduler
# [none] mq-deadline kyber bfq
# 대괄호가 현재 활성 스케줄러

영구 설정(GRUB 커널 파라미터):

# /etc/default/grub 에 추가
GRUB_CMDLINE_LINUX="elevator=none"
# 또는 udev 규칙으로 장치별 설정

데이터베이스별 스토리지 고려사항

MySQL InnoDB

InnoDB는 O_DIRECT를 기본으로 사용한다(innodb_flush_method=O_DIRECT). 페이지 캐시를 바이패스하므로 커널 메모리와의 이중 캐싱이 없다.

핵심 스토리지 파라미터
innodb_flush_method       = O_DIRECT         # 권장
innodb_io_capacity        = 2000             # SSD 기준 조정 (NVMe는 10000+)
innodb_io_capacity_max    = 4000             # 피크 시 최대 IOPS
innodb_read_io_threads    = 4               # 읽기 I/O 스레드
innodb_write_io_threads   = 4               # 쓰기 I/O 스레드
innodb_flush_log_at_trx_commit = 1          # 최고 내구성 (fsync per commit)

innodb_io_capacity는 InnoDB가 백그라운드 작업(flush, merge)에 사용할 IOPS 예산이다. 이 값이 실제 스토리지 IOPS보다 너무 낮으면 더티 페이지 플러시가 뒤처져 checkpoint age가 쌓인다.

PostgreSQL

PostgreSQL은 버퍼드 I/O를 사용한다. shared_buffers와 커널 페이지 캐시가 함께 작동한다.

핵심 스토리지 파라미터
shared_buffers            = 25% of RAM      # 권장
effective_cache_size      = 75% of RAM      # 옵티마이저 힌트 (실제 배분 아님)
wal_compression           = on              # WAL 공간 절약 (CPU 트레이드오프)
checkpoint_completion_target = 0.9         # 체크포인트 I/O를 분산
random_page_cost          = 1.1            # SSD 기준 (HDD는 4.0)

random_page_cost는 옵티마이저가 인덱스 스캔 vs 시퀀셜 스캔을 선택할 때 사용한다. NVMe라면 1.0~1.5로 설정하여 인덱스 활용을 더 적극적으로 유도할 수 있다.


클라우드 스토리지 서비스 비교

클라우드 환경에서 블록 스토리지를 선택할 때 흔히 직면하는 서비스별 차이다.

항목AWS EBS (gp3)AWS EBS (io2 BE)GCP Persistent Disk (SSD)GCP Hyperdisk Extreme
기준 IOPS3,00064,00060,000350,000
최대 처리량1,000 MB/s4,000 MB/s1,200 MB/s2,400 MB/s
레이턴시1~2 ms<1 ms1~2 ms<0.5 ms
다중 연결최대 16 인스턴스지원 (io2 ME)지원지원
적합 워크로드범용 DB고성능 OLTP범용 DB초고성능 OLTP

gp3의 실무 팁: gp3는 IOPS와 처리량을 볼륨 크기와 독립적으로 설정할 수 있다. 작은 볼륨도 높은 IOPS를 구매할 수 있어 gp2보다 비용 효율적이다.


스토리지 병목 진단

핵심 명령어

# iostat: 장치별 IOPS, 처리량, 응답시간
iostat -x -d 1 10
# %util이 100%에 가까우면 포화 상태
# await(읽기 응답시간 ms)가 급등하면 I/O 병목

# iotop: 프로세스별 I/O 사용량
iotop -o -d 1

# vmstat: 페이지 캐시 활동
vmstat 1
# bi (block in), bo (block out) 높으면 디스크 I/O 활발

# 블록 장치 스케줄러 상태
cat /sys/block/nvme0n1/queue/scheduler
cat /sys/block/nvme0n1/queue/nr_requests   # 큐 깊이

체크리스트: 스토리지 I/O 병목 의심 증상

□ iostat에서 %util 지속적으로 80% 이상
□ await(I/O 응답시간) 평소보다 10x 이상 증가
□ MySQL: innodb_buffer_pool_pages_dirty 지속 증가
□ MySQL: checkpoint age가 innodb_log_file_size에 근접
□ PostgreSQL: bgwriter checkpoint 빈도 급증
□ OS: kswapd CPU 사용률 급등 (메모리 압박으로 페이지 캐시 퇴거)
□ slow query log에 I/O 대기 관련 쿼리 증가

파일시스템 선택

데이터베이스 서버에서 파일시스템 선택은 성능과 안정성 모두에 영향을 준다.

XFS: 대규모 파일과 높은 동시성에 최적화. MySQL, PostgreSQL 공식 권장 옵션. 메타데이터 작업이 ext4보다 확장성이 높다.

ext4: 가장 널리 사용되고 검증된 파일시스템. 대부분의 DB 워크로드에서 XFS와 성능 차이가 크지 않다.

Btrfs: 스냅샷, 압축, 서브볼륨 지원. 프로덕션 DB 서버에서는 아직 XFS/ext4보다 신중하게 접근.

마운트 옵션 예시:

# XFS, 데이터베이스 최적화
/dev/nvme0n1 /var/lib/mysql xfs noatime,nobarrier,logbufs=8 0 0

# noatime: 파일 접근 시간 갱신 비활성화 (불필요한 쓰기 제거)
# nobarrier: write barrier 비활성화 (배터리 백업 없는 환경에서는 주의)

주의: nobarrier는 배터리 백업이 없는 서버에서 전원 장애 시 데이터 손상 위험이 있다. 클라우드 EBS처럼 스토리지 레이어에서 내구성을 보장하는 환경에서만 사용한다.


Open Questions

  • NVMe ZNS(Zoned Namespace) 스토리지가 데이터베이스 워크로드에 미치는 실질적 영향은 아직 연구 중.
  • 클라우드 managed DB(RDS, CloudSQL)에서 I/O 스케줄러 접근이 불가능한 경우 커널 파라미터 대신 어떤 레버를 써야 하는지에 대한 가이드라인이 충분하지 않다.

References