스토리지 시스템 기초: 블록·파일·오브젝트 스토리지와 I/O 스택
왜 DBA는 스토리지를 깊이 알아야 하는가
데이터베이스 성능 문제의 상당수는 코드가 아니라 스토리지에서 온다. 쿼리 최적화를 아무리 열심히 해도, 디스크 I/O 병목 앞에서는 무력하다. InnoDB 버퍼 풀이 충분히 크다고 해도, 데이터가 디스크에서 올라오는 순간의 레이턴시는 피할 수 없다.
DBA와 데이터 플랫폼 엔지니어가 스토리지를 알아야 하는 이유는 세 가지다. 첫째, 장애 진단이다. I/O 포화, 디스크 오류, 파일시스템 손상은 데이터베이스 장애로 직결된다. 둘째, 용량 계획이다. 데이터 증가 속도와 스토리지 특성을 이해해야 적절한 시점에 확장 결정을 내릴 수 있다. 셋째, 성능 튜닝이다. 어떤 스토리지 타입을 선택하고, I/O 스케줄러를 어떻게 설정하느냐에 따라 같은 쿼리의 응답시간이 크게 달라진다.
세 가지 스토리지 패러다임
현대 인프라에서 스토리지는 세 가지 방식으로 제공된다. 각각의 접근 모델, 강점, 약점을 명확히 구분하는 것이 설계의 출발점이다.
선택 기준 요약
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 스택을 알아야 한다. 스택은 위에서 아래로 다음과 같이 구성된다.
핵심 레이어 설명
페이지 캐시: 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의 차이
| 특성 | HDD | SATA SSD | NVMe (PCIe 4.0) |
|---|---|---|---|
| 읽기 IOPS | 100~200 | 50,000~100,000 | 500,000~1,000,000+ |
| 쓰기 IOPS | 100~200 | 30,000~80,000 | 200,000~700,000+ |
| 읽기 레이턴시 | 3~10 ms | 50~100 µs | 20~70 µs |
| 쓰기 레이턴시 | 5~15 ms | 50~150 µs | 20~100 µs |
| 순차 읽기 대역폭 | 100~200 MB/s | 500~600 MB/s | 3,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 프레임워크 기반으로 전환되었다.
권장 대상: NVMe SSD, 클라우드 인스턴스 스토리지 (AWS EBS, GCP PD 등)
echo none > /sys/block/nvme0n1/queue/scheduler
권장 대상: SATA SSD, HDD가 남아 있는 환경, Oracle DB 공식 권고.
echo mq-deadline > /sys/block/sda/queue/scheduler
권장 대상: 여러 프로세스가 디스크를 공유하는 데스크탑·컨테이너 환경.
데이터베이스 전용 서버에서는 일반적으로 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 |
|---|---|---|---|---|
| 기준 IOPS | 3,000 | 64,000 | 60,000 | 350,000 |
| 최대 처리량 | 1,000 MB/s | 4,000 MB/s | 1,200 MB/s | 2,400 MB/s |
| 레이턴시 | 1~2 ms | <1 ms | 1~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
- How to Implement Storage Performance Tuning with IO Schedulers and Mount Options
- NVMe Performance Tuning Best Practices — simplyblock
- Linux Disk I/O Scheduling Algorithms Explained — Medium
- Block Storage vs Object Storage vs File Storage — datastorage.com
- Storage stack layers and players going into 2025 — Blocks and Files
- Zero-Disk Architecture: The Future of Cloud Storage Systems — pracdata.io
- Block, Object, and File Storage in System Design — GeeksforGeeks
- Verifying the Disk I/O Scheduler on Linux — Oracle Documentation
- A week into linux storage performances Day 2: Device optimization and scheduler