•
S3는 AWS가 제공하는 서비스로 RESTful API 기반 인터페이스로 사용 가능한 객체 저장소다.
저장소 시스템 101
•
일반적으로 저장소 시스템에는 다음 세 부류가 있다.
블록 저장소
•
블록 저장소는 원시 블록을 서버에 볼륨 형태로 제공한다.
•
가장 유연하고 융통성이 높은 저장소로 서버는 원시 블록을 포맷한 다음 파일 시스템으로 이용하거나 애플리케이션에 블록 제어권을 넘겨버릴 수 있다.
◦
데이터베이스나 가상 머신같은 애플리케이션은 원시 블록을 직접 제어하여 최대한의 성능을 이끌어 낸다.
•
이외에도 블록 저장소는 고속 네트워크를 통해 연결되거나 FC, iSCSI와 같은 프로토콜 기반으로 연결될 수도 있다.
파일 저장소
•
블록 저장소 위에 구현되는 형태로 파일과 디렉토리를 손쉽게 다루는데 필요한 더 높은 수준의 추상화 수준을 제공한다.
•
데이터는 계층적으로 구성되는 디레겉리 안에 보관되며 가장 널리 사용되는 범용 저장소 솔루션이다.
•
SMB/CIFS나 NFS와 같은 파일 수준의 네트워크 프로토콜을 사용하면 하나의 저장소를 여러 서버에 동시에 붙일 수도 있다.
객체 저장소
•
데이터 영속성을 높이고 대규모 애플리케이션을 지원하며 비용을 낮추기 위해 의도적으로 성능을 희생한 형태다.
•
실시간으로 갱신할 필요가 없는 콜드 데이터 보관에 초점을 맞추며 데이터 아카이브나 백업에 주로 쓰인다. 모든 데이터를 수평적 구조 내에 객체로 보관하며 계층적 디렉토리 구조는 제공하지 않는다.
•
데이터 조작, 접근은 보통 RESTful API를 통하며 다른 유형의 저장소에 비해 상대적으로 느리다.
블록 저장소 | 파일 저장소 | 객체 저장소 | |
저장된 내용의 변경 가능성 | Y | Y | N |
비용 | 고 | 중~고 | 저 |
성능 | 중~고 혹은 최상 | 중~고 | 저~중 |
데이터 일관성 | 강력 | 강력 | 강력 |
데이터 접근 | SAS/iSCSI/FC | 표준 파일 접근, CIFS/SMB, NFS | RESTful API |
규모 확장성 | 중 | 고 | 최상 |
이용 예 | 가상 머신, 데이터베이스 등 높은 성능이 요구되는 애플리케이션 | 범용적 파일 시스템 | 이진 데이터, 구조화되지 않은 데이터 |
용어 정리
•
버킷 : 객체를 보관하는 논리적 컨테이너로 버킷 이름은 일반적으로 유일해야 한다.
•
객체 : 객체는 버킷에 저장하는 개별 데이터를 말하며 데이터와 메타데이터로 구성된다.
•
버전 : 한 객체의 여러 버전을 같은 버킷 안에 둘 수 있도록 하는 기능이다. 버킷마다 별도 설정이 가능하다. 복원 등의 기능을 지원하기 위해 존재한다.
•
URI : 객체 저장소는 버킷과 객체에 접근할 수 있도록 하는 RESTful API를 제공하기 때문에 각 객체는 API URI를 통해 고유하게 식별 가능해야 한다.
•
SLA : 서비스 수준 협약이라는 의미로 서비스 제공자와 클라이언트 사이에 맺어지는 계약이다.
◦
아마존 S3의 SLA
▪
여러 가용성 구역에 걸쳐 99.99999999%의 객체 내구성을 보장
▪
하나의 가용성 구역 전체가 소실되어도 데이터 복원 가능
▪
연간 99.9%의 가용성 제공
1단계: 문제 이해 및 설계 범위 확정
비기능 요구사항
•
100PB 데이터
•
식스 나인(99.9999%) 수준의 데이터 내구성
•
포 나인(99.99%) 수준의 서비스 가용성
•
높은 수준의 안정성과 성능은 보장하되 저장소 비용은 최대한 낮춤
대략적인 규모 추정
•
객체 저장소는 디스크 용량이나 초당 디스크 입출력이 병목이 될 가능성이 있다.
◦
디스크 용량
▪
객체 크기가 다음 특성에 따라 존재한다고 가정해보자.
•
20%는 1MB 미만
•
60%는 1MB ~ 64MB
•
20%는 64MB 이상
◦
IOPS
▪
SATA 인터페이스를 탑재하고 7200rpm을 지원하는 하드 디스크 하나가 초당 100 ~ 150회의 임의 데이터 탐색을 지원한다고 가정
•
중앙값인 0.5MB, 32MB, 200MB 용량을 기준으로 40%의 저장 공간 사용률을 유지하는 경우 저장소에 수용 가능한 객체의 수는 다음과 같이 계산할 수 있다.
◦
100PB * 0.4 / 0.2 * 0.5MB + 0.6 * 32MB + 0.2 * 200MB는 대략 6억 8천만이다.
•
이외에도 메타데이터가 대략 1KB라고 가정하면 추가적으로 0.68TB의 공간이 필요하다.
2단계: 개략적 설계안 제시 및 동의 구하기
•
설계에 영향을 끼칠 수도 있는 객체 저장소의 속성에 대해 짚고 넘어가자.
◦
객체 불변성
▪
객체 저장소와 블록, 파일 저장소의 가장 큰 차이는 변경이 불가능하다는 것이다.
◦
키-값 저장소
▪
객체 저장소의 경우, 해당 객체의 URI를 사용하여 데이터를 가져올 수 있다.
▪
이때 URI를 키로 데이터는 값에 해당한다고 볼 수 있다.
◦
저장은 1회, 읽기는 여러 번
▪
데이터 접근 패턴 측면에서 보면 쓰기는 1회, 읽기는 다회 일어난다.
◦
소형, 대형 객체 동시 지원
▪
다양한 크기의 객체를 문제 없이 지원해야 한다.
개략적인 설계안
•
로드밸런서
•
API 서비스 : IAM 서비스, 메타데이터 서비스, 저장소 서비스에 대한 호출을 조율하는 역할을 담당한다. 무상태 서비스를 원칙으로 한다.
•
IAM 서비스 : 인증, 권한 부여, 접근 제어 등을 중앙에서 맡아 처리한다.
•
데이터 저장소 : 실제 데이터를 보관하고 필요할 때마다 읽어가는 장소로 모든 데이터 관련 연산은 객체 ID를 통해 수행한다.
•
메타데이터 저장소 : 메타 데이터를 저장하는 장소다.
객체 업로드
1.
클라이언트는 bucket-to-share 버킷을 생성하기 위한 HTTP PUT 요청을 API 서비스에 보낸다.
2.
API 서비스는 IAM을 호출하여 해당 사용자가 쓰기 권한을 가졌는지 확인한다.
3.
API 서비스는 메타데이터 데이터베이스에 버킷 정보를 등록하기 위해 메타데이터 저장소를 호출한다.
•
버킷 정보가 만들어지면 그 사실을 알리는 메시지가 클라이언트에 전송된다.
4.
버킷이 만들어지고 나면 클라이언트는 script.txt 객체를 생성하기 위한 HTTP PUT 요청을 보낸다.
5.
API 서비스는 해당 사용자 신원 및 쓰기 권한 소유 여부를 확인한다.
6.
확인 결과 문제가 없으면 API 서비스는 HTTP PUT 요청 몸체에 실린 객체 데이터를 데이터 저장소로 보낸다. 데이터 저장소는 이를 저장하고 객체의 UUID를 반환한다.
7.
API 서비스는 메타데이터 저장소를 호출하여 새로운 항목을 등록한다.
객체 다운로드
1.
클라이언트는 GET 요청을 로드 밸런서로 보낸다. 로드 밸런서는 이를 API 서버로 보낸다.
2.
API 서비스는 IAM을 질의하여 사용자가 해당 버킷에 대해 읽기 권한을 가지고 있는지 확인한다.
3.
권한이 있는 경우, API 서비스는 해당 객체의 UUID를 메타데이터 저장소에서 가져온다.
4.
API 서비스는 해당 UUID를 사용해 데이터 저장소에서 객체 데이터를 가져온다.
5.
API 서비스는 HTTP GET 요청에 대한 응답으로 해당 객체 데이터를 반환한다.
3단계: 상세 설계
데이터 저장소
•
API 서비스는 요청을 다른 내부 서비스를 호출하여 처리하며 데이터 저장소는 객체를 저장하거나 가져오는 작업을 처리한다.
•
데이터 저장소의 개략적 설계
◦
데이터 라우팅 서비스
▪
데이터 노드 클러스터에 접근하기 위한 RESTful 또는 gRPC 서비스를 제공한다.
▪
배치 서비스를 호출하여 데이터를 저장할 최적의 데이터 노드를 판단하거나 데이터를 읽고, 쓰는 작업을 수행한다.
◦
배치 서비스
▪
배치 서비스는 어느 데이터 노드에 데이터를 저장할지 결정하는 역할을 담당한다.
◦
데이터 노드
▪
실제 객체 데이터가 보관되는 것으로 여러 노드에 데이터를 복제하여 안정성과 내구성을 보장하는데, 이를 다중화 그룹이라고 부른다.
▪
배치 서비스에 주기적으로 박동 메시지를 보내는 서비스 데몬을 실행시켜놓고 정보를 주기적으로 전송한다.
•
데이터 저장 흐름
1.
API 서비스는 객체 데이터를 데이터 저장소로 포워딩한다.
2.
데이터 라우팅 서비스는 해당 객체에 UUID를 할당하고 배치 서비스에 해당 객체를 보관할 데이터 노드를 질의한다. 이후 배치 서비스는 저장할 데이터 노드를 반환한다.
3.
데이터 라우팅 서비스는 저장할 데이터를 UUID와 함께 주 데이터 노드에 직접 전송한다.
4.
주 데이터 노드는 데이터를 자기 노드에 지역적으로 저장하는 한편, 두 개의 부 데이터 노드에 다중화한다. 다중화까지 성공한 후 성공 응답을 보낸다.
5.
객체의 UUID를 API 서비스에 반환한다.
메타데이터 데이터 모델
•
스키마
◦
이 데이터베이스는 다음 3가지 질의를 지원해야 한다.
▪
객체 이름으로 객체 ID 찾기
▪
객체 이름에 기반하여 객체 삽입 또는 삭제
▪
같은 접두어를 갖는 버킷 내의 모든 객체 목록 확인
버킷 내 객체 목록 확인
•
객체 저장소는 객체를 파일 시스템처럼 계층적 구조로 보관하지 않는다. 객체는 s3://{버킷 이름}/{객체 이름}의 수평적 경로로 접근한다.
•
사용자가 버킷 내 객체들을 잘 정리할 수 있도록 S3는 접두어라는 개념을 지원하는데, 이를 잘 사용하면 디렉터리와 비슷하게 데이터를 정리할 수 있다.
4단계: 마무리
•
S3와 유사한 객체 저장소 시스템을 설계해보았으며 구체적인 사항은 생략했다.
•
객체 저장소의 핵심은 객체 업로드, 다운로드, 객체 목록 표시, 객체 버전 등의 기능이라 이들을 위주로 정리하였으며 이외의 내용들은 다음을 고려해보면 좋을 것이다.
◦
데이터가 저장소와 메타데이터 저장소가 어떻게 구현되는지
◦
데이터가 데이터 저장소에 어떻게 영속적으로 저장되는지
◦
데이터의 안정성과 내구성을 높이기 위한 다중화와 소거 코드
◦
거대한 데이터는 어떻게 효율적으로 업로드할 수 있는지
◦
객체 버전 관리에 따른 불필요한 데이터는 어떻게 가비지 컬렉트할 것인지