Storage Terminology Map
block storage, object storage, NAS, SAN, DAS, NVMe, Ceph, VAST…
Intro
솔직히 띄엄띄엄 들어는 봤지만 “하나하나 차이를 설명해보세요” 하면 더듬거린다.
나도 처음엔 각 단어들을 머리에 집어넣고 외우려고 했는데, 그렇게 외우면 오래 못 간다.
개인적으로는 이걸 한 줄로 놓고 외우려고 하는 게 문제 같다.
NAS와 object storage는 비교가 된다. 둘 다 “disk가 network 너머에 있을 때 뭘 주고받나”를 다룰 때 나오는 개념이기 때문이다.
아무래도 이런 경우는 외우기가 수월하다. 그런데 NAS와 NVMe는 비교가 안 된다. 이건 아예 다른 집 얘기다.
SAN과 Ceph도 마찬가지
정리하는 방법은 단어를 외우는 게 아니라 “어떤 질문에 대한 답인가?”이다.
이 질문들을 기억하자.
- 클라이언트가 무엇을 요청하는가?
- disk가 어디 있는가?
- 무엇으로 꽂혀 있는가?
- 그 disk가 무슨 일을 하는가?
Pushing the Disk Away
질문들을 처음부터 나열하면 외워야 할 목록이 늘어날 뿐이다. disk를 한 홉씩 멀리 밀다 보면 이해하기가 수월하다.
그 전에, 한 가지만 머리에 넣고 가자.
핵심은 물리 disk다. 저장을 한다는 건 원격이든 로컬이든 어딘가의 물리 공간에 집어넣는다는 것이고, 이 개념은 NAS든 NAS 할아버지든 똑같다.
서버 한 대, 그 안에 SSD 한 장이 있다. 프로그램이 파일을 읽으면 이런 경로를 탄다.
read()
→ VFS
→ filesystem (ext4)
→ block layer
→ NVMe driver
→ PCIe
→ SSD
VFS는 Virtual File System으로, Linux kernel 안에 있는 추상화 계층이고, 모든 filesystem에 대한 interface이다. ext4는 fourth extended filesystem이라는 물건인데, 그냥 Linux filesystem이라고 생각해도 무방하다.
자, 여기서 각 단계가 아는 것이 다르다.
ext4는 “이 경로에 있는 파일의 512번째 바이트”를 “이 디바이스의 몇 번 block”으로 바꿀 줄 안다.
여기서 block은 disk를 똑같은 크기로 잘라놓은 칸 하나를 말한다. ext4는 보통 4KB씩 자르고 0번부터 순서대로 번호를 매긴다. disk 자신도 따로 번호를 갖는데 그게 LBA(Logical Block Address)다. 둘 사이는 block layer가 번역한다. filesystem의 block 번호는 partition 시작점 기준, disk의 LBA는 장치 시작점 기준.
그 아래로 내려가면 파일이라는 개념은 사라지고 번호 붙은 칸과 바이트만 남는다.
더 아래는 하드웨어 얘기다. PCIe는 SSD가 CPU에 붙어 있는 통로고, DMA는 그 통로로 데이터를 실제로 옮기는 방식이다.
driver가 “몇 번 칸부터 이만큼 읽어서 메모리 이 주소에 넣어라”라고 명령을 큐에 적어두면, SSD가 그걸 가져가서 메모리에 직접 써넣는다.
수 GB를 읽는데 CPU가 바이트를 하나하나 날라야 한다면 그것대로 일이 안 되니까, CPU는 다 끝났다는 신호만 받고 데이터는 CPU를 건너뛰고 간다.
이 부분은 GPU Cluster Hardware Map에 더 자세히 적어뒀다.
이제 SSD를 서버 밖으로 빼보자. (그냥 그렇다고 해보자)
Hop 1
disk를 서버 밖으로 빼서 별도 enclosure에 담고 케이블로 연결한다.
enclosure는 CPU 없이 disk만 담는 상자다. HDD를 담으면 JBOD, SSD를 담으면 JBOF라고 부른다.
아직까지 위에서 말한 경로는 그대로다. ext4는 여전히 이 서버에서 돌고, 저쪽은 번호 붙은 칸을 내줄 뿐이다.
케이블이 길어졌다는 것 말고는 달라진 게 없다. 이 구성에 붙은 이름이 SAN이다.
Hop 2
filesystem까지 저쪽으로 넘긴다. 이제 이 서버는 block 번호를 모른다.
“이 경로 열어줘”라고 요청하고 파일을 받는다. 오가는 단위가 바뀌었다.
이 구성이 NAS다
Hop 3
directory tree를 버린다. 경로도 없고 파일 중간을 고치는 것도 없다.
HTTP로 key를 주면 blob 하나를 통째로 주고받는다.
이게 object storage다
세 홉을 지나면서 disk가 멀어졌고, 오가는 단위가 block에서 파일로, 파일에서 blob으로 바뀌었다.
Where the Filesystem Runs
위에서 말했던 질문들을 다시 가져와보자.
- 클라이언트가 무엇을 요청하는가?
- disk가 어디 있는가?
- 무엇으로 꽂혀 있는가?
- 그 disk가 무슨 일을 하는가?
첫 번째 질문은 “클라이언트가 무엇을 요청하는가”다.
block, file, object. 무조건 셋 중 하나다. (그냥 그렇게 생각하자)
그런데 셋을 각각 외울 필요가 없다. 하나의 질문이 셋을 다 결정한다.
filesystem이 어디서 도는가?
filesystem은 세 가지 일을 한다.
- 이름을 block 위치로 바꾸고(directory tree와 inode),
- 크기와 권한과 시각 같은 metadata를 들고 있고,
- 여러 요청이 같은 파일을 건드릴 때 순서를 중재한다.
이 셋을 어느 쪽 기계에서 하느냐가 클라이언트가 받는 것을 정한다.
- DAS: Direct Attached Storage, 서버에 직접 꽂힌 storage
- SAN: Storage Area Network, storage 전용으로 깐 network
- NAS: Network Attached Storage, network에 붙어 있는 storage
- NFS: Network File System, network 너머의 filesystem을 쓰는 프로토콜
| filesystem 위치 | 서버가 내주는 것 | 붙은 이름 |
|---|---|---|
| 클라이언트에서 돈다 | 번호 붙은 block의 배열 | DAS, SAN |
| 서버에서 돈다 | 파일 | NAS, NFS |
| 아예 없다 | key에 매달린 blob | Object |
Block
“클라이언트가 무엇을 요청하는가?”, 클라이언트가 block을 요청했다.
서버는 번호가 붙은 고정 크기 칸의 배열을 내준다.
요청할 때 “512번 칸부터 8칸 읽어줘” 같은 식으로 요청한다.
파일이라는 개념이 없고 이름도 없다. 그 위에 무엇을 얹을지는 전적으로 클라이언트가 정한다.
그래서 block을 직접 쓰는 쪽은 자기만의 배치 규칙을 가진 소프트웨어다.
데이터베이스는 페이지 레이아웃을 스스로 관리하니 filesystem을 끼우면 오히려 손해다.
virtual machine의 disk 이미지도 마찬가지고, 무엇보다 filesystem 자신이 block 위에 얹힌다.
여기서 block의 성격 하나가 따라 나온다.
두 서버가 같은 block volume에 동시에 붙으면 데이터가 깨진다.
각 서버의 filesystem이 자기 메모리에 든 cache를 진실이라고 믿기 때문이다.
A가 inode를 고쳐 cache에 들고 있는 동안 B는 옛날 block을 읽고, B가 자기 판단으로 쓰면 A가 모르는 사이에 덮인다.
서로의 존재를 알 방법이 없다.
붙는 것 자체를 막지는 않는다. EBS Multi-Attach 같은 기능이 있고 iSCSI LUN도 여러 서버가 붙일 수 있다.
Block Storage 자체는 filesystem을 내주지 않는다. 클라이언트의 filesystem을 쓴다.
read()
→ VFS
→ filesystem (ext4)
→ block layer
→ iSCSI initiator
→ network ← "LBA 512번부터 8칸"이 오간다
→ 저쪽 SSD
ext4도 block layer도 여전히 이쪽 서버에서 돈다.
File
“클라이언트가 무엇을 요청하는가?”, 클라이언트가 file을 요청했다.
이 경우에는 filesystem이 서버에서 돈다. 클라이언트는 경로를 말하고 파일을 받는다.
read()
→ VFS
→ NFS client
→ network ← "/data/app.log 열어줘"가 오간다
→ 저쪽 서버
→ filesystem (ext4)
→ block layer
→ NVMe driver
→ SSD
block일 때 저쪽 SSD에 그쳤는데 여기서는 VFS 밑이 통째로 저쪽으로 넘어갔다.
이쪽에 남은 NFS client는 이름만 filesystem이다. VFS에 filesystem인 척 등록해두고, block 번호는 계산하지 않고 요청을 network 너머로 넘긴다.
directory tree를 관리하는 주체가 한 곳이니 여러 클라이언트가 동시에 붙어도 서버가 순서를 잡아줄 수 있다.
NAS가 여러 서버에 같은 volume을 물릴 수 있는 이유
다만 완전한 중재는 아니다. 매번 서버에 물어보면 느리니 클라이언트도 cache를 한다.
NFS가 오래 쓰는 타협이 close-to-open consistency다. 파일을 닫을 때 변경분을 서버로 밀고 열 때 서버 것을 확인한다.
그 사이에 다른 클라이언트가 쓴 내용은 보이지 않을 수 있다.
Object
filesystem이 없다. key를 주면 blob을 주는 flat한 공간만 있다.
PUT /bucket/key
→ HTTP client
→ network ← key와 blob이 통째로 오간다
→ 저쪽 서버
첫 줄부터 다르다. read()가 아니다. syscall이 아니라 HTTP 요청이라 kernel의 VFS를 아예 지나가지 않는다.
filesystem도 block layer도 없다. block에서는 클라이언트에 있었고 file에서는 원격으로 넘어갔는데, 여기서는 클라이언트 스택에서 통째로 빠졌다.
저쪽 서버 안에도 결국 물리 disk가 돌아가고 있지만 그건 저쪽 사정이고, 클라이언트가 아는 건 저쪽 서버라는 한 줄이 전부다.
logs/2026/07/app.log 같은 key를 보면 directory처럼 보이지만 /는 그냥 글자다.
logs/라는 것이 어딘가에 존재하지 않는다.
콘솔에서 폴더처럼 보여주는 건 prefix로 묶어 그려주는 것뿐이고, 그래서 “directory 이름 바꾸기”가 없다.
안에 든 key를 전부 새 key로 복사하고 옛 key를 지우는 수밖에 없다.
파일 중간을 고치는 것도 없다. 통째로 올리고 통째로 받는다. directory tree와 lock과 부분 수정을 다 버린 대가로 얻은 것이 무한에 가까운 확장성이다. 중재할 상태가 없으면 node를 늘리는 데 걸리는 게 없다.
DAS, SAN, NAS
자, 두 번째 질문은 “disk가 어디 있는가”다.
앞의 “클라이언트가 무엇을 요청하는가?”는 무엇을 주고받는지의 문제고, 여기는 물리적으로 어디에 놓여 있는지의 문제다.
DAS
Direct Attached Storage. 이름에서 알 수 있듯이 서버에 직접 꽂힌 disk다. 케이블이 서버 안에서 끝난다.
가장 빠르고 가장 안 유연하다. network를 타지 않으니 지연이 낮지만, 그 서버가 죽으면 disk에 접근할 방법이 없다.
서버를 옮기면 데이터도 같이 옮겨야 한다.
cloud의 instance store나 on-prem의 서버에 꽂힌 NVMe SSD가 여기에 해당한다.
SAN
Storage Area Network. “스토리지 영역 네트워크”라고 말하면 직관적이진 않다.
LAN(Local Area Network)이나 WAN(Wide Area Network)의 AN을 그대로 가져와서 그렇다.
그냥 storage 장치들만 모아놓은 전용 network 공간으로 이해하면 조금 감이 온다.
즉 disk를 별도 장비에 모아두고 block을 network로 나른다.
여기서 나오는 단어가 LUN(Logical Unit Number)이다.
storage 장비가 자기 disk 풀에서 잘라 서버 하나에 내주는 하나의 block device를 가리킨다.
서버 입장에서는 마치 DAS처럼 그냥 disk 한 장이 꽂힌 것으로 보인다.
lsblk에 뜨고 partition을 나눌 수 있고 filesystem을 만들 수 있다.
실제로는 광케이블 너머 어딘가에 있다는 사실이 감춰진다.
여기서 block을 나르는 방식이 두 개가 있다.
FC(Fibre Channel)는 전용 케이블과 전용 스위치를 쓴다. 서버에는 HBA라는 전용 카드를 꽂는다. 프로토콜 자체가 무손실을 전제로 설계됐다.
iSCSI는 SCSI 명령을 TCP에 실어 보낸다. 일반 Ethernet으로 되니까 싸고 별도 장비가 필요 없다.
NAS
Network Attached Storage. Direct → Network로 바뀌었다. 대충 감이 오겠지만 저쪽에서 filesystem이 돌고 이쪽은 경로로 요청한다.
프로토콜은 NFS와 SMB. 앞 절에서 본 file 모델이 그대로 여기 얹힌다.
이름도 비슷한데 NAS의 프로토콜로 NFS를 사용하니 NFS와 NAS를 자주 헷갈리는 이유이기도 하다
NAS는 “disk가 어디 있는가”에 대한 답이고, NFS는 그 위에서 도는 프로토콜임을 명심하자.
“NAS를 NFS로 마운트했다”는 가능하지만 “NAS냐 NFS냐”는 성립하지 않는다.
Media and Interface
세 번째 질문은 “무엇으로 꽂혀 있는가”다.
앞의 두 질문과 살짝 결이 다르고 모호하다.
어떤 맥락이냐면, “로컬 disk도 NVMe일 수 있고 SAN 장비 안의 disk도 NVMe일 수 있다.” 같은 말이다.
여기를 정리해두지 않으면 SSD vs NVMe 같은 성립하지 않는 비교에 계속 발이 걸린다.
- HDD(Hard Disk Drive): 흔히 말하는 hard disk.
- SSD(Solid State Drive): Solid State는 전자공학 용어고, 움직이는 부품 없이 고체 상태의 반도체로 동작한다는 뜻이다.
SSD 설명이 “뭔 말이야?” 싶을 텐데 그냥 기계적 동작이 없다고 생각해도 된다.
HDD는 판이 돌고 헤드가 움직인다. 원하는 위치에 헤드를 옮기는 시간이 나머지를 압도해서, 순차 읽기와 랜덤 읽기의 차이가 백 배 단위로 벌어진다.
SSD는 움직이는 부품이 없다. 그렇다고 요청 하나가 무한정 빨라지는 건 아니다. NAND die 하나를 읽는 데 수십 마이크로초가 걸리고, 이 시간은 어떻게 해도 안 줄어든다.
die는 웨이퍼에서 잘라낸 반도체 칩 한 조각을 말한다. SSD 하나에 NAND die가 수십 개씩 들어가고, 각 die는 서로 독립적으로 읽고 쓴다.
그래서 빨라지는 방법이 하나뿐이다. 여러 die를 동시에 굴리는 것.
요청을 하나씩 보내면 die 하나가 일하는 동안 나머지는 논다. 32개를 한꺼번에 던지면 32개가 같이 읽는다. 제품 페이지에 적힌 IOPS 수치는 이 상태에서 잰 값이다.
즉 SSD는 “하나를 얼마나 빨리 처리하나”가 아니라 “동시에 몇 개를 밀어넣을 수 있나”로 성능이 갈린다.
병렬에 관한 이야기이다. 32개를 동시에 던져도 각각이 빨라지는 건 아니고, throughput이 증가한다는 말.
Cable and Command Interface
케이블 규격과 명령 규격은 다른 것이다. SATA는 케이블 규격이고, 그 위에서 도는 명령 규격은 AHCI다.
위에서 말한 SSD는 빨라지려면 여러 요청을 동시에 밀어넣어야 한다는 걸 기억하자.
AHCI는 2004년에 HDD를 전제로 설계됐다. 큐가 하나, 깊이가 32다. 헤드가 하나뿐인 장치에 요청을 백 개씩 몰아줄 이유가 없었으니 합리적인 설계였다.
문제는 SSD가 여기 꽂혔을 때다. 내부는 병렬인데 요청이 한 줄로 들어오면 대부분의 채널이 논다.
NVMe는 2011년에 그 병목을 없애려고 나왔다. 규격상 큐를 65,535개까지, 큐마다 명령을 65,536개까지 담을 수 있다.
실제 장치는 그렇게까지 안 만들고 보통 큐 16개에서 256개, 깊이 32에서 2,048개 사이다. 그래도 AHCI와는 자릿수가 다르다.
| 큐 개수 | 큐당 깊이 | |
|---|---|---|
| AHCI (SATA) | 1 | 32 |
| NVMe (규격 상한) | 65,535 | 65,536 |
| NVMe (실제 장치) | 16 ~ 256 | 32 ~ 2,048 |
그리고 NVMe는 PCIe에 직접 붙는다. SATA 컨트롤러라는 중간 단계가 없다.
Three Meanings of NVMe
이 단어가 헷갈리는 건 실제로 세 가지를 가리키기 때문이다.
첫째, 명령 프로토콜이다. 위에서 본 큐 구조와 명령 집합을 정의한 NVM Express 규격.
둘째, 물리 form factor와 연결 방식이다. M.2, U.2, EDSFF 같은 모양으로 PCIe lane에 직결되는 것.
셋째, 그냥 “빠른 SSD”라는 뭉뚱그림이다. 제품 페이지에서 가장 많이 쓰이는 뜻이고 가장 부정확하다.
그래서 SSD vs NVMe는 성립하지 않는다. SSD는 매체고 NVMe는 말 거는 방식이라서, NVMe로 연결된 SSD가 있을 뿐이다.

SSD 쪽에 깔린 검은 칩이 앞에서 말한 die다. 저게 여러 개라서 요청을 몰아줘야 제 성능이 나고, 그래서 큐가 몇 개인지가 문제가 된다.
Boot Disk and Root Disk
네 번째 질문은 “그 disk가 무슨 일을 하는가”다. 같은 block volume이라도 OS가 사는 곳과 데이터가 사는 곳은 다루는 방식이 다르다.
이 단어들이 유독 헷갈리는 이유가 있다. cloud 문맥에서는 boot disk와 root disk가 같은 말인데, Linux 안에서는 /boot와 /가 다른 것을 가리킨다. 두 문맥이 섞이면 답이 안 나온다.
/boot는 kernel 이미지와 bootloader 설정이 들어가는 작은 partition이다. bootloader가 kernel을 읽어야 하는데 그 시점엔 kernel이 아직 없으니, 아무 도움 없이도 읽힐 만큼 단순해야 한다.
/는 root filesystem이고 OS 전체가 사는 곳이다. /usr, /etc, /var가 다 여기 있다. /boot는 보통 이 tree 안의 한 지점에 마운트된다. 둘은 포함 관계지 같은 것이 아니다.
Cloud Naming
같은 물건을 세 회사가 다르게 부른다.
| cloud | 부르는 이름 |
|---|---|
| AWS | root volume |
| GCP | boot disk |
| Azure | OS disk |
셋 다 같다. instance를 띄울 때 이미지가 복사되어 들어가고 그 안에 /boot와 /가 다 들어 있는 block volume 하나다. “boot disk와 root disk가 뭐가 다르냐”는 질문의 답이 문맥마다 달랐던 건 이 때문이다. cloud 콘솔에서는 같은 것을 가리키고, Linux 안에서는 다른 것을 가리킨다.
Why Root Disk Is Always Block
bootloader에는 NFS 클라이언트가 없다. TCP/IP 스택도 없다. 있는 것은 disk에서 섹터를 읽는 능력 정도다. 그래서 OS가 사는 곳은 block이어야 한다.
예외도 실제로 쓰인다. PXE로 kernel을 network에서 받아 NFS를 root로 마운트하거나, firmware에 iSCSI initiator를 넣어 LUN에서 부팅한다. GPU cluster에서 node에 disk를 안 꽂고 굴릴 때 쓰는 방법이다.
Volume Lifetime
instance store는 instance가 멈추면 내용이 없어진다. 하드웨어에 붙어 있으니 다른 물리 서버로 옮겨가면 따라오지 못한다.
EBS 같은 network block volume은 남는다. 다만 root volume은 기본값이 DeleteOnTermination=true라 instance를 종료하면 같이 지워진다. 데이터 volume은 기본값이 반대고, 이 차이 때문에 사고가 난다.
container의
/는 또 다른 이야기다. 이미지 레이어를 overlayfs로 겹친 것이라 disk partition이 아니고 부팅 과정도 없다. Cgroup and Namespace에 정리해뒀다.
Cloud and On-Prem
같은 물건이 세계마다 다른 이름을 갖는다. on-prem 경험이 있는 사람이 cloud에서 헤매고 그 반대도 마찬가지인 이유다.
| on-prem | cloud (AWS 기준) | 무엇을 내주나 |
|---|---|---|
| 서버 내장 NVMe SSD | instance store | block, 로컬 |
| SAN LUN (FC, iSCSI) | EBS | block, network 너머 |
| NFS 서버, NAS appliance | EFS | file |
| MinIO | S3 | object |
여기서 cloud가 감춘 것이 하나 있다. EBS는 network 너머의 block인데 로컬 disk처럼 보인다. lsblk에 그냥 뜨고 partition도 나뉘고 filesystem도 만들어진다. 물리적으로는 SAN에 가까운데 interface가 그 사실을 숨긴다.
그래서 “로컬 disk인 줄 알았는데 왜 이렇게 느리지”가 생긴다. 학습 데이터를 EBS에 두고 GPU를 굶기는 상황이 대표적이다. instance store와 EBS를 구별해야 하는 건 성능 숫자 이전에 이 둘이 애초에 다른 자리에 있는 물건이기 때문이다.
What to Ask
새 단어를 만났을 때 순서대로 던질 질문이다.
- 클라이언트가 무엇을 받나? block인가, 파일인가, key에 매달린 blob인가
- disk가 어디 있나? 서버 안인가, 전용 network 너머인가, 일반 network 너머인가
- 무엇으로 연결됐나? PCIe, SAS, Ethernet, FC, InfiniBand
- 그 disk가 무슨 일을 하는가? boot disk인가, 데이터가 사는 곳인가, 버려도 되는 곳인가