한물간 회전식 디스크 수천만 개로 행성 규모의 저장소를 운영하는 네 가지 설계 장치
인터넷에 올라가는 사진과 동영상, 수많은 서비스의 백업 파일은 결국 비슷한 곳으로 흘러 들어간다. 그 대표 주자가 아마존이 운영하는 객체 저장 서비스 S3(Simple Storage Service)다. 흥미로운 점은 이 거대한 시스템이 최신 SSD(Solid State Drive)가 아니라, 이제는 한물갔다고 여겨지는 회전식 하드디스크(HDD, Hard Disk Drive) 위에서 돌아간다는 사실이다. 느리기로 유명한 부품으로 어떻게 이만한 속도를 감당하는지, 그 설계를 한 단계씩 따라가 본다.
설계를 이해하려면 이 시스템이 다루는 양이 어느 정도인지 먼저 감을 잡아야 한다. 2026년 3월 출시 20주년 시점에 아마존이 공개한 수치를 보면, S3는 500조 개가 넘는 객체를 담고 있고 전 세계에서 초당 2억 건 이상의 요청을 처리한다. 저장된 데이터 총량은 수백 엑사바이트(EB, 1엑사바이트는 약 100만 테라바이트)에 이르고, 전송 처리량은 초당 1페타바이트를 넘어선다. 이 모든 일이 39개 리전, 123개 가용영역에 흩어진 수천만 개의 하드디스크 위에서 벌어진다.
품질 지표도 함께 보면 설계의 목표가 뚜렷해진다. S3가 내세우는 내구성은 이른바 11 나인, 즉 99.999999999퍼센트다. 1년 동안 1,000만 개의 객체를 맡겼을 때 평균적으로 단 하나가 손실될까 말까 한 수준이다. 한편 저장 단가는 2006년 출시 당시 1기가바이트에 15센트였던 것이 지금은 2센트 남짓으로, 약 85퍼센트 떨어졌다. 규모는 폭발적으로 커졌는데 신뢰성은 올라가고 값은 내려간 것이다. 이 세 마리 토끼를 동시에 잡기 위해 등장한 것이 바로 하드디스크다.
이유는 단순하다. 같은 용량이라면 하드디스크가 SSD보다 훨씬 싸기 때문이다. 수백 엑사바이트를 모두 SSD로 채운다면 비용이 감당하기 어려운 수준으로 치솟는다. 문제는 하드디스크가 느리다는 점인데, 정확히 어디가 느린지가 핵심이다.
하드디스크는 회전하는 자기 원판(플래터) 위를, 끝에 헤드가 달린 팔(액추에이터 암)이 오가며 데이터를 읽고 쓴다. 원하는 데이터를 읽으려면 팔이 해당 트랙으로 물리적으로 이동(탐색)한 뒤, 원판이 그 지점까지 돌아오기를 기다려야 한다. 이 기계적 동작 때문에 임의의 위치를 마구 찾아 읽는 작업은 느릴 수밖에 없다.
턴테이블에 올린 레코드판을 떠올리면 쉽다. 특정 곡으로 건너뛰려면 바늘이 달린 팔을 그 자리로 옮기고, 판이 그 지점까지 돌기를 기다려야 한다. 노래를 순서대로 죽 트는 일(순차 읽기)은 빠르지만, 이 곡 저 곡을 마구 골라 듣는 일(임의 접근)은 매번 팔을 옮기느라 굼뜨다. 하드디스크의 약점이 바로 여기에 있다.
구체적으로 보면, 하드디스크가 1초에 처리할 수 있는 임의 접근 횟수(IOPS, Input/Output Operations Per Second)는 오랫동안 120회 안팎에 머물러 있다. 반면 순차적으로 죽 읽을 때의 처리량은 초당 수백 메가바이트에 이른다. 용량은 해마다 늘어 지금은 한 개에 26테라바이트짜리가 쓰이고 업계 로드맵은 200테라바이트를 바라보지만, 임의 접근 속도는 거의 제자리다. 그래서 용량이 커질수록 데이터 1바이트당 접근 속도는 오히려 나빠지는 역설이 생긴다. 단순화하면 저장된 데이터 2테라바이트마다 1초에 한 번꼴로만 접근을 허락하는 셈이다. S3 설계는 이 약점을 정면으로 부정하지 않는다. 대신 약점을 인정하고, 디스크의 수를 곱해서 우회한다.
디스크 한 대의 한계는 그 한 대 안에서는 풀 수 없다. 그래서 S3는 큰 객체를 여러 조각으로 잘라 수많은 디스크에 나눠 저장한다. 1테라바이트짜리 파일을 디스크 한 대에만 담으면, 읽기 속도는 그 한 대의 최대 처리량(초당 수백 메가바이트)에 묶인다. 그러나 같은 파일을 수천 대에 쪼개 두면, 모든 디스크에서 자기 몫의 조각을 동시에 꺼낼 수 있다. 전체 읽기 속도는 디스크 한 대의 속도가 아니라 그 디스크들의 속도를 합한 값이 된다.
마트 계산대를 떠올려 보자. 손님 100명을 점원 한 명이 받으면 줄이 한없이 길어진다. 계산대를 다섯 개로 늘려 손님을 나눠 세우면 같은 인원을 대략 5분의 1 시간에 처리한다. 하드디스크 한 대의 느린 속도는 그대로지만, 여러 대를 동시에 돌리면 전체 처리량이 그만큼 곱해진다. 느린 부품을 빠르게 만드는 게 아니라, 많이 깔아 병렬로 돌리는 전략이다.
한 가지 덧붙이면, 아주 작은 객체에는 정반대 처리를 한다. 자잘한 파일 수백 개를 제각각 따로 저장하면 디스크의 접근 횟수만 잡아먹어 비효율적이다. 그래서 S3 내부 저장 엔진은 작은 객체 여러 개를 큰 파일 하나로 묶어 순차적으로 기록한다. 큰 것은 쪼개고 작은 것은 묶는다. 방향은 반대지만 목적은 같다. 느린 임의 접근을 최대한 피하고 디스크를 효율적으로 쓰자는 것이다.
조각을 여러 디스크에 흩뿌리기로 했다면, 다음 질문이 곧바로 따라온다. 수천만 개나 되는 디스크 중에서 어느 디스크에 저장할지 어떻게 고를 것인가. 가장 간단한 답은 무작위 선택이다. 그런데 순수한 무작위로 고르면 운이 나쁜 디스크에 데이터가 우연히 몰리는 일이 생긴다. 어떤 디스크는 거의 비어 있는데 어떤 디스크는 요청이 쏠려 처리가 밀린다. 이렇게 과부하가 걸린 디스크를 흔히 뜨거운 디스크라 부르고, 여기서 지연이 발생한다.
해법은 의외로 간단하다. 저장할 곳을 무작위로 한 개만 고르지 말고, 무작위로 두 개를 뽑은 뒤 둘 중 덜 찬 쪽에 넣는 것이다. 선택지를 하나에서 둘로 늘렸을 뿐인데, 디스크들의 사용률이 놀라울 만큼 고르게 맞춰진다.
마트에서 계산할 때 줄 하나를 눈 감고 고르면 하필 가장 긴 줄에 설 수 있다. 대신 가까운 줄 두 개를 슬쩍 보고 더 짧은 쪽에 서면, 줄을 일일이 비교하지 않고도 대기 시간이 눈에 띄게 평탄해진다. 모든 줄의 길이를 재서 가장 짧은 곳을 찾을 필요도 없다. 딱 두 줄만 비교하면 충분하다.
이 방법에는 견고한 수학적 뿌리가 있다. 공을 무작위로 통에 하나씩 던질 때, 통 하나가 떠안는 최대 개수는 통 수가 늘수록 함께 늘어난다. 그런데 던질 때마다 통 두 개를 뽑아 덜 찬 쪽에 넣으면, 최대 부하가 지수적으로 줄어든다는 사실이 1994년 이론 컴퓨터과학 학회에서 처음 증명됐고, 이후 미첼마처(Michael Mitzenmacher)의 연구로 일반화됐다. 이 결과는 두 선택의 힘(power of two choices)이라는 이름으로 불리며, 부하 분산이 필요한 거의 모든 분산 시스템에 응용된다. 2020년에는 이 업적에 컴퓨팅 분야의 권위 있는 상이 수여됐다. S3는 이 단순한 원리를 디스크 배치에 그대로 가져다 쓴다.
디스크는 언젠가 반드시 고장 난다. 수천만 개를 운영하면 고장은 매일 일어나는 일상이다. 그래서 데이터를 한 곳에만 두어서는 안 되고, 어딘가에 여분을 마련해 둬야 한다. 가장 단순한 방법은 똑같이 복제해 두는 것이지만, 이러면 용량이 두 배, 세 배로 불어난다. 수백 엑사바이트 규모에서 이 낭비는 막대하다.
S3가 택한 방법은 소거 부호화(erasure coding)다. 데이터를 5조각으로 나눈 뒤, 그 조각들로부터 계산해 낸 여분 조각(패리티) 4개를 더 만들어 모두 9조각으로 흩어 둔다. 그러면 9조각 가운데 아무 5조각만 살아 있어도 원본을 완벽하게 되살릴 수 있다. 최대 4조각이 한꺼번에 사라져도 데이터는 안전하다. 그런데도 차지하는 용량은 두 배가 아니라 9를 5로 나눈 1.8배에 그친다.
좌표 평면에 점 다섯 개를 찍으면, 그 다섯 점을 모두 지나는 매끄러운 곡선이 단 하나로 정해진다. 학창 시절 점 몇 개로 함수를 결정하던 그 원리다. 소거 부호화는 원본 데이터를 이런 곡선이라고 보고, 그 곡선 위의 점을 9개 미리 찍어 흩어 둔다. 그중 어느 점이든 5개만 회수하면 곡선 전체가 복원되고, 곧 원본을 되살릴 수 있다. 어떤 점이 사라졌는지는 중요하지 않다. 다섯 개가 남았다는 사실만 중요하다.
이 방식에는 덤이 따라온다. 읽기 속도가 빨라지고, 특히 지연의 꼬리가 짧아진다. 원본을 조립하려면 9조각 중 5조각만 모으면 되므로, 마침 느려진 디스크 하나가 늑장을 부려도 그 디스크를 기다릴 필요가 없다. 다른 디스크의 조각을 먼저 모아 곧장 복원하면 된다. 가장 느린 디스크에 전체 속도가 발목 잡히는 일을 구조적으로 막는 셈이다.
앞의 세 장치가 디스크를 영리하게 쓰는 기술이라면, 마지막 장치는 규모 그 자체에서 나온다. 어느 한 고객의 트래픽만 보면 매우 들쭉날쭉하다. 평소엔 한산하다가 특정 순간 폭증하는 식이다. 그런데 수백만 고객의 워크로드를 한데 합치면, 한쪽의 갑작스러운 폭증이 다른 쪽의 한산함과 상쇄된다. 서로 무관한 수많은 요청이 평균을 이루면서, 시스템 전체가 느끼는 부하는 뾰족한 봉우리 없이 매끄럽게 펴진다.
고속도로를 위에서 내려다본다고 하자. 차 한 대 한 대는 끼어들고 가속하고 급정거하기를 반복한다. 하지만 도로 전체의 차량 흐름은 그보다 훨씬 완만하게 오르내린다. 개별 차량의 변덕이 한데 섞이며 평탄해지기 때문이다. S3가 다루는 트래픽도 마찬가지다. 사용자가 많아질수록 전체 흐름은 오히려 예측하기 쉬워진다.
이 평탄화 덕분에 S3는 용량을 훨씬 자신 있게 계획하고 효율적으로 운영할 수 있다. 들쭉날쭉한 봉우리를 일일이 떠받칠 여유분을 과도하게 쌓아 둘 필요가 없기 때문이다. 이는 작은 시스템은 누릴 수 없는, 행성 규모에서만 얻어지는 이점이다.
네 가지 장치 위에는 눈에 잘 띄지 않는 운영 장치들이 더 얹혀 있다. 우선 디스크를 주기적으로 검사해 고장 조짐이 보이면 그 안의 데이터를 미리 다른 디스크로 옮긴다. 또한 새로 투입된 디스크는 아직 신뢰성이 검증되지 않은 위험 구간으로 본다. 그래서 갓 들어온 디스크에는 한 객체의 조각을 하나만 올리도록 배치를 조절한다. 혹시 그 디스크가 곧 죽더라도, 잃는 것은 그 객체의 조각 하나뿐이어서 나머지 조각으로 복원할 수 있다.
쓰기 작업도 하드디스크의 성질에 맞춰 설계됐다. S3의 저장 엔진은 들어오는 데이터를 기존 자리에 끼워 넣는 대신, 로그처럼 끝에 차곡차곡 이어 붙인다. 임의의 위치를 헤집는 대신 순차적으로 기록하는 방식이라, 하드디스크가 그나마 빠른 순차 처리량을 최대한 살릴 수 있다.
여기까지의 발상은 거창해 보이지만, 핵심 아이디어는 가정용 장비에서도 그대로 만난다. 디스크 여러 개를 묶어 쓰는 RAID(Redundant Array of Independent Disks)가 그것이다. RAID 0은 데이터를 여러 디스크에 쪼개 저장(스트라이핑)해 입출력 속도를 디스크 수만큼 끌어올린다. 다만 여분이 없어 디스크 하나가 고장 나면 데이터를 잃는다. RAID 5는 여기에 패리티 한 조각을 더해, 디스크 하나가 고장 나도 나머지로 복원할 수 있게 한다. S3가 쓰는 소거 부호화의 축소판인 셈이다.
네트워크 저장장치(NAS, Network Attached Storage)에는 이런 RAID 기능이 대개 기본으로 들어 있다. 중요한 자료를 안전하면서도 빠르게 두고 싶다면, S3가 수천만 개 규모로 펼친 그 아이디어를 디스크 몇 개 수준에서 그대로 체험해 볼 수 있다.
S3 설계가 주는 교훈은 분명하다. 부품의 한계를 부정하는 대신, 한계를 인정하고 수를 곱해 우회한다는 것이다. 느린 하드디스크 한 대는 여전히 느리다. 그러나 쪼개고, 고르게 흩뿌리고, 잃지 않도록 부호화하고, 수많은 사용자의 짐을 한데 합치면, 오래된 기술도 가장 현대적인 시스템을 떠받칠 수 있다.