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

NVMe·SSD·HDD 심화: 내부 구조, 마모 관리, ZNS

왜 스토리지 내부 구조가 DBA에게 중요한가

"NVMe가 빠르니까 그냥 쓰면 된다"는 생각은 절반만 맞다. 새 디스크는 빠르다. 그런데 6개월 후 같은 디스크의 IOPS가 절반으로 줄었다면? 쓰기 레이턴시가 갑자기 치솟는다면? 이유를 모르면 대응이 불가능하다.

내부 구조를 알아야 하는 이유는 세 가지다.

  • 쓰기 성능 저하 진단: SSD가 시간이 지나면서 느려지는 메커니즘
  • WAF(Write Amplification) 이해: 내가 1MB를 썼는데 디스크는 왜 3MB를 기록하는가
  • 수명 계획: 언제 디스크를 교체해야 하는지 근거 있게 판단하기

HDD의 구조와 한계

HDD는 자성 코팅된 금속 플래터(platter)를 읽기·쓰기 헤드(head)가 회전하며 접근하는 기계 장치다. 데이터베이스 성능에 직접 영향을 주는 레이턴시는 세 부분으로 나뉜다.

Seek Time
헤드가 원하는 트랙으로 이동
평균 3~10 ms
기계적 이동 → 예측 불가
+
Rotational Latency
원하는 섹터가 헤드 아래로 도달
7,200 RPM → 평균 4.2 ms
반 바퀴 최대 8.3 ms
+
Transfer Time
실제 데이터 전송
4KB 기준 ~0.01 ms
전체 중 가장 짧음
랜덤 4KB I/O 합계: 7~15 ms → 초당 66~140 IOPS
HDD 레이턴시 구성 요소

B-Tree 인덱스 탐색, InnoDB 페이지 읽기 같은 랜덤 I/O는 모두 이 제약에 직면한다. 순차 I/O(WAL 쓰기, 테이블 풀 스캔)에서는 HDD가 여전히 합리적이다. 2026년 기준 16~20TB HDD의 GB당 비용은 NVMe의 약 1/8~1/10 수준으로, 대용량 콜드 데이터나 백업 스토리지에서는 여전히 선택지가 된다.


NAND Flash 기초: 셀 타입 비교

SSD의 저장 매체는 NAND Flash다. 셀(cell) 하나에 몇 비트를 저장하느냐에 따라 SLC·MLC·TLC·QLC로 나뉜다. 비트 수가 많을수록 밀도와 비용 효율이 높아지지만, 내구성과 성능이 떨어진다.

SLC Single-Level Cell 1 bit / 셀 0 1 2 voltage levels P/E 사이클: ~100,000회 읽기 레이턴시: ~25 µs 쓰기 레이턴시: ~250 µs 엔터프라이즈 캐시 초고빈도 쓰기 비용: 가장 높음 MLC Multi-Level Cell 2 bits / 셀 00 01 10 11 4 voltage levels ~10,000회 ~50 µs ~600 µs 엔터프라이즈 일반 고빈도 OLTP 비용: 높음 TLC Triple-Level Cell 3 bits / 셀 8 voltage levels (000~111) 레벨 간 마진 좁아짐 → 노이즈 민감도 ↑ 1,000~3,000회 ~75 µs ~900 µs 소비자·중간급 기업 일반 OLTP 비용: 중간 QLC Quad-Level Cell 4 bits / 셀 16 voltage levels (0000~1111) 레벨 간 마진 매우 좁음 → 쓰기 속도 큰 폭 저하 100~1,000회 ~100 µs ~2,000+ µs 대용량 읽기 집중 콜드 데이터·DWH 비용: 가장 낮음 P/E 사이클: P/E 사이클: 읽기 레이턴시: 읽기 레이턴시: 읽기 레이턴시: 읽기 레이턴시: 쓰기 레이턴시: 쓰기 레이턴시: 쓰기 레이턴시: 쓰기 레이턴시: P/E 사이클:
NAND 셀 타입별 전압 레벨과 특성 비교

P/E 사이클(Program/Erase cycle): NAND Flash는 블록(block) 단위로만 지울 수 있으며, 지울 수 있는 횟수에 물리적 한계가 있다. 이 한계를 초과하면 해당 블록은 불량(bad block)이 된다. TLC 기준 1,000~3,000회는 일반적인 운영 수명에서 충분하지만, 지속적인 랜덤 쓰기가 많은 워크로드에서는 관리가 필요하다.


SSD 내부 구조

SSD는 크게 네 개 구성 요소로 이루어진다.

호스트 (OS) LBA 요청 read / write PCIe / NVMe 큐 깊이 65,535 (SATA: 32) 컨트롤러 (Controller) NVMe 큐 처리기 Submit Queue / Completion Queue 처리 FTL (Flash Translation Layer) LBA → Physical Page 주소 매핑 테이블 웨어 레벨링 가비지 컬렉션 ECC (에러 정정 코드) DRAM 캐시 매핑 테이블 보관 (1TB → ~1GB DRAM) NAND 채널 인터페이스 병렬 채널 인터리빙 NAND Flash 패키지 / 다이 / 플레인 블록 (Block) 지우기 단위 (수백 KB~MB) P/E 사이클 한계 적용 페이지 (Page) 읽기/쓰기 단위 (4KB~16KB) 쓰기 전 블록 erase 필요 셀 (Cell) SLC/MLC/TLC/QLC SLC 캐시 영역 최초 쓰기 버퍼, 소진 후 속도↓
SSD 내부 구조 아키텍처

컨트롤러 (Controller)

컨트롤러는 SSD의 두뇌다. 호스트의 논리 블록 주소(LBA)를 실제 NAND 물리 주소로 변환하고, 여러 NAND 채널을 병렬로 운영하며, FTL 알고리즘을 실행한다. 좋은 컨트롤러는 낮은 레이턴시와 일관된 성능을 제공하고, 불량 컨트롤러는 동일한 NAND를 써도 성능이 크게 다르다.

DRAM 캐시

FTL이 관리하는 매핑 테이블(LBA → 물리 주소)을 RAM에 보관한다. NAND 1TB당 약 1GB DRAM이 필요하다. DRAM-less SSD는 매핑 테이블을 NAND에서 직접 읽어야 하므로 랜덤 읽기 레이턴시가 높고 예측하기 어렵다. 데이터베이스 서버에는 DRAM 캐시가 있는 모델을 선택해야 한다.

SLC 캐시

TLC·QLC SSD는 일부 NAND 영역을 SLC 모드로 사용하여 최초 쓰기 속도를 높인다. 이 영역이 소진되면 TLC/QLC 속도로 쓰기가 이루어져 성능이 급격히 낮아진다. OLTP처럼 지속적인 쓰기가 있는 환경에서 SLC 캐시 크기가 실질적 지속 쓰기 성능을 결정한다.


FTL의 세 가지 핵심 역할

1. 주소 매핑: Out-of-Place Write

NAND Flash는 덮어쓰기(overwrite)가 불가능하다. 파일시스템이 "A 주소에 새 데이터 쓰기"를 요청해도 SSD는 같은 물리 위치를 즉시 수정할 수 없다. 반드시 빈 페이지에 먼저 써야 한다.

기존 데이터가 LBA 100에 있음 → 물리 페이지 P50에 저장
호스트: "LBA 100에 새 데이터 써라"
FTL:
  1. 새 빈 페이지 P80 선택
  2. 새 데이터를 P80에 씀
  3. 매핑 테이블 업데이트: LBA 100 → P80
  4. P50을 "Invalid(무효)" 표시
  → P50은 GC가 처리할 때까지 공간을 차지함

이것이 Out-of-Place Write다. 이 때문에 무효 페이지가 쌓이고, 가비지 컬렉션이 필요해진다.

2. 웨어 레벨링 (Wear Leveling)

모든 P/E 사이클을 균등하게 분산한다.

  • 동적 웨어 레벨링(Dynamic): 새 쓰기를 가장 적게 사용된 블록으로 보낸다. 자주 쓰이는 데이터에 적용.
  • 정적 웨어 레벨링(Static): 잘 변경되지 않는 콜드 데이터도 주기적으로 새 블록으로 이동시켜, 기존 블록의 P/E 카운트가 쌓이는 것을 방지한다.

정적 웨어 레벨링이 없으면 자주 쓰이는 영역만 먼저 닳고, 나머지 영역은 여전히 신품 상태로 남는 불균형이 발생한다.

3. 가비지 컬렉션 (Garbage Collection)

Invalid 페이지가 쌓이면 사용 가능한 빈 블록이 부족해진다. GC는 여러 블록에 흩어진 유효 페이지를 새 블록 하나에 모아 기록하고, 기존 블록을 통째로 지운다(erase).

블록 A: 유효 페이지 4개 + Invalid 페이지 8개
블록 B: 유효 페이지 3개 + Invalid 페이지 9개

GC 실행:
  → 유효 페이지 7개를 새 블록 C에 복사
  → 블록 A와 B를 erase → 빈 블록으로 복구
  → 복사 과정에서 7 페이지 추가 쓰기 발생

이 "복사 쓰기"가 Write Amplification의 원인이다.


Write Amplification Factor (WAF)

WAF = (실제 NAND에 기록된 총 데이터) / (호스트가 요청한 쓰기 데이터)

이상적: WAF = 1.0
실제 OLTP 워크로드: 일반적으로 2.0~5.0

WAF가 높아지는 주요 원인:

  1. 디스크 사용률이 높을수록: 빈 블록이 적으면 GC가 자주 실행되고 더 많은 유효 페이지를 복사한다
  2. 소규모 랜덤 쓰기: 4KB 랜덤 쓰기가 많으면 한 블록에 무효 페이지가 빠르게 누적된다
  3. 쓰기 집중 워크로드: SLC 캐시가 소진된 TLC/QLC에서 GC 압박이 가중된다

WAF와 데이터베이스 운영의 관계:

  • InnoDB의 더블 라이트 버퍼, redo log, undo log는 모두 쓰기를 발생시킨다. 호스트가 인식하는 쓰기보다 실제 NAND 마모는 항상 크다.
  • WAF=3이면 "1TB 쓰기 보증" 디스크는 실질적으로 333GB 호스트 쓰기만 지원한다는 의미다.

WAF 완화 전략

Over-provisioning (OP): 디스크 용량의 20~30%를 사용하지 않으면 GC가 사용할 여유 공간이 생겨 WAF가 낮아진다. 포맷 후 70~80%만 사용하는 설정이 실무 권고다.

TRIM/Unmap: OS가 파일을 삭제할 때 SSD에 해당 LBA가 더 이상 유효하지 않다고 알린다. SSD가 미리 GC를 준비할 수 있어 효율이 높아진다.

# TRIM 활성화 확인 (XFS/ext4)
findmnt -O discard
# 또는 /etc/fstab에 discard 옵션 추가

# 수동 TRIM 실행 (cron으로 주 1회 권장)
fstrim -v /var/lib/mysql

정렬된 순차 쓰기: WAL(Write-Ahead Log)처럼 순차적으로 쓰는 패턴은 WAF가 낮다. InnoDB redo log, PostgreSQL WAL이 이 설계를 따르는 이유 중 하나다.


SSD 수명 예측과 모니터링

TBW와 수명 계산

제조사는 TBW(Total Bytes Written, 총 보증 쓰기량)를 보증한다.

이론적 수명 (년) = TBW / (일일 쓰기 GB × 365)
실질적 수명 (년) = TBW / (일일 쓰기 GB × WAF × 365)

예시:
  1TB TLC NVMe, TBW=600TB, 일 30GB 쓰기, WAF=2
  → 600,000 GB / (30 × 2 × 365) = 27.4년
  → 넉넉하지만, 쓰기가 100GB/일이면 → 8.2년

NVMe SMART 모니터링

# nvme-cli 설치 후
nvme smart-log /dev/nvme0n1

# 주요 필드
# Percentage Used       : 현재 예상 수명 소모 비율 (100%면 TBW 소진)
# Data Units Written    : 총 누적 쓰기 (512B 단위 × 1000)
# Media and Data Integrity Errors : 수정 불가 에러 수

Prometheus exporter를 통해 nvme_percent_used를 수집하면 수명 소모를 대시보드로 추적할 수 있다.


ZNS(Zoned Namespace): FTL 오버헤드를 줄이는 새로운 접근

기존 SSD는 호스트에게 "아무 LBA나 자유롭게 써도 됩니다"라는 블록 스토리지 추상화를 제공한다. 그 대가로 DRAM 매핑 테이블, GC 오버헤드, WAF가 발생한다.

ZNS(Zoned Namespace) 는 이 추상화를 일부 포기하는 대신 호스트 소프트웨어가 데이터 배치를 직접 제어하게 한다.

전통적 블록 SSD 호스트 랜덤 LBA 쓰기 FTL DRAM 매핑 테이블 GC + 웨어 레벨링 1TB당 ~1GB DRAM NAND Flash 내부 GC 쓰기 발생 (WAF↑) 단점: DRAM 필요, GC 지연, WAF 높음 ZNS SSD 호스트 Zone 내 순차 쓰기 Zone Reset 명시 호출 (호스트가 GC 담당) 경량 FTL Zone 단위 매핑만 유지 DRAM 대폭 절감 NAND Flash 내부 GC 최소화 (WAF↓) 장점: DRAM 절감, WAF 낮음, 예측 가능한 레이턴시
ZNS vs 전통적 SSD 비교

ZNS의 핵심 규칙

  • Zone: 수십~수백 MB 크기의 논리 주소 범위. 내부에서 순차 쓰기만 허용된다.
  • Write Pointer: Zone 내 현재 쓰기 위치. 순차로만 증가한다. 랜덤 쓰기 시도는 에러를 반환한다.
  • Zone Reset: 호스트가 명시적으로 호출해 Zone 전체를 지운다. 전통 SSD의 내부 GC가 하던 일을 호스트가 담당한다.

ZNS와 데이터베이스 현황

RocksDB (Meta, TiKV, CockroachDB 등에서 사용)는 ZenFS 플러그인을 통해 ZNS를 네이티브로 지원한다. LSM-tree의 레벨별 순차 쓰기 패턴이 ZNS Zone과 잘 맞기 때문이다. WAF를 1.1~1.3 수준으로 낮추는 벤치마크 결과가 보고되었다.

MySQL InnoDB, PostgreSQL 같은 전통적 RDBMS는 랜덤 업데이트를 허용하는 구조라 ZNS를 직접 활용하려면 중간 레이어(zonefs, f2fs)가 필요하다. 2026년 기준 연구 및 초기 실험 단계이며, 프로덕션 적용 사례는 제한적이다.


데이터베이스 관점의 디스크 선택 기준

워크로드권장이유
OLTP (InnoDB, PostgreSQL)TLC NVMeP/E 사이클 충분, 비용 합리적
쓰기 집중 OLTP (PB급)MLC NVMe (엔터프라이즈)높은 내구성, 예측 가능한 수명
OLAP / DWH (읽기 집중)QLC NVMe 또는 SATA SSD쓰기 적음, 비용 효율 우선
백업 · 아카이브 · Data LakeHDD 또는 오브젝트 스토리지용량 당 비용 최소화
로그 · 임시 데이터TLC SATA SSD레이턴시보다 비용 균형

QLC 주의사항: SLC 캐시가 소진되면 TLC 대비 쓰기 레이턴시가 2~5배 상승한다. 지속적인 랜덤 쓰기가 있는 OLTP 주 데이터파일에는 QLC 사용을 피한다.


운영 체크리스트

□ NVMe 사용 서버: I/O 스케줄러 none 설정 확인
    cat /sys/block/nvme0n1/queue/scheduler
□ 디스크 사용률 75% 미만 유지 (Over-provisioning 확보)
□ OS TRIM 활성화 확인
    findmnt -O discard  또는  cron fstrim -v /
□ NVMe SMART로 주기적 수명 점검
    nvme smart-log /dev/nvme0n1 | grep -E 'Percentage|Data Units'
□ OLTP에 QLC 사용 시: SLC 캐시 크기 확인, 지속 쓰기 성능 측정
□ DRAM-less SSD 회피: 데이터베이스 서버에는 DRAM 캐시 모델 선택
□ 베터리 없는 서버: nobarrier 마운트 옵션 사용 금지

Open Questions

  • ZNS가 MySQL InnoDB 또는 PostgreSQL에 실질적으로 통합되는 시점은 아직 불확실하다. 현재는 연구 및 파일시스템 레이어를 통한 간접 활용 단계다.
  • QLC SSD의 WAF를 실시간으로 수집해 DBA 알림에 통합하는 표준 메트릭 경로가 아직 확립되지 않았다.

References