객체 저장의 진화는 초기 Ceph 및 Swift 구현과 같은 중앙 집중식 메타데이터 데이터베이스에서 하이퍼스케일을 처리할 수 있는 분산 아키텍처로 이동하였습니다. 이러한 전환은 POSIX 유사 의미론(원자적 이름 바꾸기, 엄격한 직렬화)과 수십억 개의 키를 SSD, HDD, 및 테이프 계층에서 관리하는 데 필요한 수평 확장성 간의 근본적인 긴장을 도입했습니다. 핵심 문제는 전통적인 2단계 커밋(2PC) 프로토콜 또는 Paxos 기반의 글로벌 합의의 지연 페널티를 발생시키지 않으면서 분산 노드 간의 동시 변화를 조정하는 것입니다.
해결책은 각 샤드가 Raft 프로토콜을 사용하여 그 경계 내에서 일관성을 보장하는 특정 네임스페이스 파티션을 관리하는 샤드 합의 아키텍처를 필요로 합니다. 메타데이터 라우터 계층은 디렉터리 접두사에 따라 클라이언트 요청을 전송하며, 일관성 해싱을 활용하여 범위 쿼리의 지역성을 유지하면서 수평 확장을 가능하게 합니다. 성능을 위해 핫 메타데이터는 레벨 캐시에 resides하며, 이에는 Redis가 L1 역할을 하고 로컬 RocksDB가 L2 내구성을 담당합니다. 차가운 메타데이터는 S3에있는 Apache Parquet 파일로 압축되어 저장 비용을 줄이면서 내구성을 희생하지 않습니다.
AWS S3에서 사설 하이브리드 클라우드로 전환하는 미디어 회사는 인코딩 프로필, DRM 키 및 생애 주기 상태를 추적하는 메타데이터와 함께 20억 개의 비디오 세그먼트를 관리해야 했습니다. 그들의 초기 아키텍처는 자동 샤딩을 사용하는 MongoDB를 사용했지만, 청크 마이그레이션 중에 예측할 수 없는 지연 스파이크(100-500ms)가 발생하고 서로 다른 샤드 간의 원자적 거래가 부족하여 동시 폴더 이동 중 데이터 손상이 발생했습니다.
솔루션 1: CockroachDB (분산 SQL)
이 접근 방식은 Google Spanner 유사 아키텍처를 통해 본래 수평 확장을 제공하고 직렬화된 격리를 제공했습니다. 주요 장점은 메타데이터에 대한 복잡한 분석 쿼리에서 친숙한 SQL 인터페이스를 제공한 것입니다. 그러나 시스템은 다중 지역 합의 복제를 통해 높은 쓰기 증폭(3-5배)을 나타내었고, 쓰기 경합이 최고조에 달할 때의 전염성 콘텐츠 업로드에서 지연이 지속적으로 20ms를 초과했습니다. 페타바이트 규모의 메타데이터 저장에 대한 라이센스 비용은 조직에 대한 경제적 실행 가능성을 입증하지 못했습니다.
솔루션 2: Apache Cassandra와 경량 트랜잭션 (LWT)
Cassandra는 대량의 쓰기 처리량과 조정 가능한 일관성을 제공하며, Paxos 기반 LWT가 선형화된 작업을 제공합니다. 이 기술은 단일 실패 지점 없이 고속 메타데이터 스트림을 흡수하는 데 뛰어났습니다. 불행히도 Paxos 지연은 평균 15ms였으며 동시 액세스 하에서 크게 악화되었고, "업로드 날짜별 목록" 쿼리에 대한 보조 인덱싱에는 비용이 많이 드는 전체 테이블 스캔이 필요하여 대화형 사용자 경험에는 적합하지 않았습니다.
솔루션 3: Raft로 사용자 디렉토리당 커스텀 샤드
이 설계는 각 사용자 디렉토리를 특화된 Raft 합의 그룹에 매핑하여 채널 내의 작업(액세스의 주요 단위)이 선형화되고 로컬 디스크 액세스로 인해 빠르도록 보장합니다. 이 아키텍처는 서로 다른 네트워크 간 조정 없이 샤드 로컬 트랜잭션을 통해 원자적 이름 바꾸기를 지원했습니다. 비록 이것이 전염성 디렉토리(핫스팟)의 재샤딩 논리에 복잡성을 도입하고 복잡한 클라이언트 측 라우팅 라이브러리를 요구했지만, 비디오 콘텐츠가 제작자별로 자연스럽게 분할되는 워크로드 패턴에 완벽하게 부합했습니다.
결과: 이 시스템은 전염성 이벤트 동안 초당 80,000개의 메타데이터 작업을 성공적으로 유지했으며 P99 지연 시간은 3ms 미만이었습니다. 자동 계층화 정책에 따라 노후화 된 콘텐츠의 90%가 차가운 저장소로 이동하여 전체 인프라 비용을 60% 줄였으며 활성 콘텐츠에 대한 엄격한 일관성 보증을 유지했습니다.
인기 있는 객체가 만료되거나 업데이트될 때 메타데이터 캐시에서 스탬피드 문제를 방지하는 방법은 무엇인가요?
지원자는 종종 단순한 TTL 기반 만료를 제안하지만 스탬피드 보호를 고려하지 않습니다. 올바른 접근 방식은 캐시 항목이 짧은 수명의 임대 토큰을 소지하는 임대 기반 캐싱을 구현하여 임대 소유자만 백엔드에서 갱신하고 다른 항목은 잠시 동안 구식 데이터를 제공하는 것입니다. 여기에 확률적 조기 만료(TTL에 무작위 지터 추가)와 단일 비행 패턴(Go의 singleflight 패키지에서 구현됨)을 결합하여 동시 동일 요청을 단일 백엔드 쿼리로 축소하여 캐시 누락 시 데이터베이스 과부하를 방지합니다.
클러스터 다운타임 없이 라이브 샤드 분할(재샤딩) 작업 동안 메타데이터 일관성을 보장하는 전략은 무엇인가요?
많은 사람들은 마이그레이션 중 쓰기를 중지해야 한다고 제안하지만, 이는 가용성 요구 사항을 위반합니다. 적절한 기술은 섀도 인덱싱 및 더블 라이트 프로토콜을 사용합니다. 먼저, Raft 로그 배송을 사용하여 소스 샤드의 지연 복제로 새로운 대상 샤드를 인스턴스화합니다. 동기화되면 새로운 샤드에 쓰기 경로를 전환하되 구 샤드에 톰스톤 로그를 유지하여 후행 읽기를 처리하기 위한 유예 기간을 설정합니다. etcd와 같은 조정 서비스가 라우팅 테이블을 원자적으로 업데이트하며, MVCC 타임스탬프는 전환 중 읽기가 일관된 스냅샷을 보도록 보장하고 원자적으로 절단이 완료될 때까지 분할 경계를 초과하는 요청을 거부합니다.
비동기 가비지 수집이나 계층화 마이그레이션이 조용히 실패했을 때 메타데이터 인덱스를 물리적 저장소 계층과 어떻게 조정하나요?
이를 위해 사건 소스 접근 방식과 분산 트랜잭션을 위한 사가 패턴이 필요합니다. 메타데이터 서비스는 도메인 이벤트(예: "TieringInitiated")를 Apache Kafka 로그에 방출하며, 저장소 소비자는 아이도포턴트 콜백을 통해 성공적인 처리를 수락합니다. 저장소 계층이 지정된 타임아웃 내에 객체를 마이그레이션하지 못하는 경우 메타데이터 서비스는 Saga 타임아웃 이벤트를 수신하고 메타데이터 상태를 "HOT"으로 되돌리기 위한 보상 거래를 트리거합니다. 추가적으로, Merkle 트리를 사용한 백그라운드 재조정 스캐너를 구현하여 메타데이터와 물리적 저장소 HEAD 요청 간의 차이를 효율적으로 식별하고 전체 테이블 스캔 없이 불일치를 수리합니다.