강한 일관성을 지키는 클라우드 스토리지 (Windows Azure Storage, SOSP 2011)
Blob, Table, Queue 를 하나의 스택으로 제공하는 Windows Azure Storage 의 스탬프 구조와 3계층(프런트엔드, 파티션, 스트림) 설계를 공개한 논문입니다. 지금 Azure Storage 계정과 LRS, GRS 같은 중복성 옵션의 뿌리입니다.
출처
| 항목 | 내용 |
|---|---|
| 원제 | Windows Azure Storage: A Highly Available Cloud Storage Service with Strong Consistency |
| 저자 | Brad Calder, Ju Wang, Aaron Ogus, Niranjan Nilakantan, Arild Skjolsvold, Sam McKelvie 외 21명 (모두 Microsoft) |
| 실린 곳 | Proceedings of the 23rd ACM Symposium on Operating Systems Principles (SOSP '11), 143~157쪽 |
| 발표 | 2011년 10월 (포르투갈 카스카이스) |
| DOI | https:// |
| 원문 | ACM Digital Library |
| 이용 조건 | ACM 저작권 (Copyright 2011 ACM). 개인 및 강의용 복제만 무료로 허용 |
참고 이 페이지는 원문 번역이 아니라 한국어 해설이에요. 정확한 표현과 수치는 원문을 확인하세요.
한눈에
- 2008년 11월부터 운영된 Windows Azure Storage(WAS)의 내부 구조를 처음 자세히 공개한 논문입니다.
- 데이터 센터 안의 저장 단위를 "스토리지 스탬프"라는 랙 묶음으로 나누고, 그 위를 위치 서비스가 묶는 구조를 제안합니다.
- 스탬프 안은 프런트엔드, 파티션 계층, 스트림 계층의 3계층이며, 스탬프 안 복제는 동기식, 스탬프 사이 복제는 비동기식으로 나누어 강한 일관성과 재해 복구를 함께 얻습니다.
- 추가 전용(append-only) 저장, 확장(extent) 봉인, 범위 파티션, 소거 코딩 같은 설계는 이후 Azure Storage 전체의 기본 틀이 되었습니다.
왜 나왔나
클라우드 스토리지는 아주 많은 고객의 데이터를 한 하드웨어 풀에 담아야 합니다. 그런데 당시 많은 대규모 저장소는 가용성을 위해 최종 일관성(eventual consistency)을 택했고, 애플리케이션 개발자가 충돌과 지연된 반영을 직접 처리해야 했습니다. Microsoft 내부 고객(Bing, Xbox, Zune 등)과 외부 고객이 원한 것은 조금 달랐습니다. 저자들은 고객 요구를 네 가지로 정리합니다. 쓰기가 끝나면 바로 보이는 강한 일관성과 조건부 연산, 계정 이름 하나로 어디서든 접근하는 전역 네임스페이스, 지역 단위 재해에 대비하는 복구, 그리고 여러 고객이 같은 장비를 나눠 쓰는 멀티 테넌시입니다.
논문은 Bing 이 Facebook 과 Twitter 게시물을 수집해 검색에 반영하는 엔진을 예로 듭니다. 이 서비스는 게시물을 15초 안에 검색 가능하게 만들고, 복제 전 기준 약 350TB 를 저장하며, 최대 초당 약 4만 건, 하루 20억~30억 건의 트랜잭션을 처리했다고 적습니다.
핵심 아이디어
전역 네임스페이스
모든 데이터는 계정이름.<서비스>.core.windows.net/파티션이름/객체이름 형태의 URI 로 접근합니다. 계정 이름은 DNS 로 해석되어 그 계정이 사는 기본 스탬프를 가리키고, 파티션 이름은 여러 서버에 부하를 나누는 단위가 되며, 객체 이름은 파티션 안의 개별 객체를 구분합니다. 같은 파티션 이름을 공유하는 객체끼리는 원자적 트랜잭션이 가능합니다. Blob 은 Blob 이름 자체가 파티션 이름이고, Table 은 (파티션 이름, 객체 이름)이 기본 키이며, Queue 는 큐 이름이 파티션 이름입니다.
스토리지 스탬프와 위치 서비스
스탬프는 10~20개의 랙으로 이루어진 클러스터이고, 랙마다 저장 노드 18대가 있으며 랙 하나가 하나의 장애 도메인입니다. 1세대 스탬프는 원시 용량 약 2PB, 차세대는 최대 30PB 를 담는다고 적혀 있습니다. 스탬프는 용량의 약 70% 까지만 쓰도록 운영하고, 80% 를 넘지 않게 합니다. 남는 20% 는 디스크 바깥쪽 트랙만 쓰는 성능 확보와 랙 장애 대비용입니다.
위치 서비스(Location Service)는 모든 스탬프와 계정 네임스페이스를 관리합니다. 새 계정을 어느 스탬프에 둘지 정하고, 스탬프가 70% 에 이르면 계정을 다른 스탬프로 옮깁니다. 위치 서비스 자체도 두 지리적 위치에 분산되어 있습니다.
세 계층과 두 복제 엔진
스탬프 안은 아래에서부터 스트림 계층, 파티션 계층, 상태 없는 프런트엔드 계층으로 나뉩니다. 복제는 두 종류입니다. 스탬프 안 복제는 스트림 계층이 맡고 쓰기 요청의 응답 경로 위에서 동기적으로 일어나 하드웨어 장애에 대한 내구성을 줍니다. 스탬프 사이 복제는 파티션 계층이 맡고 비동기로 일어나 지역 재해 대비와 계정 이전에 쓰입니다. 이렇게 역할을 나눈 덕분에 스탬프 안에서는 강한 일관성을 유지하면서도, 지역 간 지연이 쓰기 응답 시간에 끼어들지 않습니다.
스트림 계층
스트림 계층은 추가만 가능한 분산 파일 시스템입니다. 스트림은 확장(extent)들을 가리키는 포인터의 순서 있는 목록이고, 확장은 블록의 연속입니다. 블록은 읽기와 쓰기의 최소 단위로 최대 약 4MB 이며 블록마다 체크섬이 붙습니다. 확장은 복제 단위로 스탬프 안에 기본 3개 복제본을 두고, 파티션 계층이 쓰는 확장의 목표 크기는 1GB 입니다.
스트림 매니저(SM)는 Paxos 로 복제되는 관리 서버로, 확장 배치와 재복제, 가비지 컬렉션, 소거 코딩 일정을 맡지만 쓰기 경로에는 끼지 않습니다. 논문은 SM 이 스탬프당 최대 5천만 개 확장과 10만 개 스트림을 32GB 메모리 안에서 관리할 수 있다고 적습니다.
쓰기는 1차 확장 노드가 오프셋과 순서를 정하고, 세 복제본에 모두 기록된 뒤에만 성공을 돌려줍니다. 확장이 열려 있는 동안 1차 노드는 바뀌지 않으므로 리스(lease)가 필요 없습니다. 장애가 나면 SM 은 연락이 닿는 복제본 중 가장 짧은 커밋 길이로 그 확장을 봉인(seal)하고 새 확장을 엽니다. 봉인된 복제본은 비트 단위로 똑같아지며, 봉인된 확장은 나중에 소거 코딩으로 저장 비용을 3배에서 1.3~1.5배 수준으로 줄일 수 있습니다. 이 소거 코딩은 다음 논문 Azure Storage 의 소거 코딩에서 자세히 다룹니다.
느린 디스크 대응도 실용적입니다. 이미 100ms 이상의 I/O 가 대기 중이거나 대기 요청이 200ms 를 넘으면 그 디스크에 새 I/O 를 보내지 않습니다. 또 확장 노드마다 저널 전용 드라이브를 두어, 커밋 로그 추가 지연을 평균 30ms 에서 6ms 로 줄였다고 합니다.
파티션 계층
파티션 계층은 Blob, Table, Queue 를 "객체 테이블(Object Table)"이라는 거대한 정렬 테이블로 표현합니다. 객체 테이블은 키 범위로 잘린 RangePartition 들로 나뉘고, 파티션 서버(PS)가 각각 맡습니다. 파티션 매니저(PM)는 Paxos 기반 락 서비스로 리더를 뽑고, 부하에 따라 파티션을 옮기거나(load balance) 쪼개거나(split) 합칩니다(merge). 파티션 서버는 쓰기를 커밋 로그에 남긴 뒤 메모리 테이블에 반영하고, 주기적으로 체크포인트를 만드는 LSM 트리 방식으로 동작합니다. 쪼개기와 합치기는 데이터를 복사하지 않고 스트림 메타데이터만 바꾸는 MultiModify 연산으로 빠르게 처리합니다.
스탬프 사이 복제는 기본 스탬프에서 커밋된 변경을 보조 스탬프로 비동기 전송하며, 평균 약 30초 안에 보조 스탬프에 반영된다고 적습니다. 갑작스러운 장애 조치에서는 최근 변경이 유실될 수 있지만, 계획된 이전에서는 유실이 없고 URI 도 바뀌지 않습니다.
설계 선택과 교훈
8장은 운영 경험을 정리합니다. 계산과 저장을 분리해 각각 따로 늘릴 수 있게 한 점, 해시 대신 범위 파티션을 택해 계정 단위 격리와 나열을 쉽게 만든 점(순차 키에 몰리는 문제는 파티션 이름에 해시를 붙이는 식으로 완화), 추가 전용 설계가 스냅샷과 소거 코딩과 장애 진단을 쉽게 만든 대신 가비지 컬렉션 I/O 비용을 낳은 점, 프런트엔드에서 계산한 체크섬을 모든 계층이 검증하는 종단 간 무결성 등입니다. CAP 정리에 대해서는, 스탬프 안에서는 계층 분리와 정의된 장애 모델 덕분에 강한 일관성과 높은 가용성을 함께 제공한다고 설명합니다.
실험과 결과
6장은 실제 운영 중인 공유 스탬프에서 1Gbps NIC 를 가진 VM 으로 처리량을 잽니다. 100GB 크기 테이블 하나에 1KB 엔터티를 무작위로 읽고 쓰면 VM 1대에서 16대까지 처리량이 거의 선형으로 늘었고, 100개 엔터티를 묶은 배치 쓰기는 단건 쓰기보다 약 3배 높은 처리량을 냈습니다(그림 6). 4MB Blob 무작위 읽기와 쓰기는 VM 8대까지 선형으로 늘다가 클라이언트 네트워크 한계에서 완만해졌습니다(그림 7).
7장의 표 1은 내부 서비스의 사용 비율을 보여 줍니다. 전체 요청은 Blob 17.9%, Table 46.88%, Queue 35.22% 였지만 용량은 Blob 이 70.31% 를 차지했습니다. Xbox 게임 저장은 요청의 99.68% 가 Blob 이었고, Bing 수집 엔진은 요청의 98.48% 가 Table 이었습니다. 운영 규모로는 생산 환경 원시 용량 70PB, 추가로 수백 PB 를 준비 중이라고 적혀 있습니다.
지금 Azure 에서는
이 논문의 구조는 지금의 Azure Storage 계정(Blob, Table, Queue)에 그대로 이어집니다. 계정이름.blob.core.windows.net 같은 엔드포인트가 논문의 전역 네임스페이스이고, 한 지역 안에서 3개 복제본을 두는 로컬 중복 스토리지(LRS)는 스탬프 안 동기 복제, 다른 지역으로 비동기 복제하는 지역 중복 스토리지(GRS)는 스탬프 사이 복제에 해당합니다. GRS 에서 지역 장애로 장애 조치를 하면 아직 복제되지 않은 최근 쓰기가 유실될 수 있다는 공식 문서의 설명도 이 비동기 설계에서 나옵니다.
함께 읽기
- 스토리지 계정: 이 사이트의 기능 문서
- Azure Storage 의 소거 코딩: 봉인된 확장을 LRC 로 줄이는 방법
- Socrates: Azure Storage 위에 데이터베이스 저장 계층을 다시 쌓은 사례
- 저자 발표 영상 (SOSP 2011)
- Azure 블로그의 논문 소개 글