호드의 스토리지 플랫폼은 인터링크 블롭으로 구성된 대규모 데이터 구조 조작을 지원하도록 설계되었습니다. 블롭은 변경 불가능 하며, 데이터의 임의 블록과 다른 블롭에 대한 0개 이상의 외부 레퍼런스로 구성됩니다.
그러한 데이터 구조에 대한 엔트리 포인트는 레퍼런스, 즉 데이터 구조의 루트에서 블롭에 대한 레퍼런스를 유지하는 사용자 정의된 이름입니다. 레퍼런스에 의해 직간접적으로 참조되지 않은 모든 노드는 가비지 컬렉션의 대상이 됩니다.
히스토리
호드의 스토리지 시스템은 에픽의 GitHub repository의 바이너리를 다운로드하는 데 사용되는 GitSync 툴이 진화한 것으로 볼 수 있습니다. 에픽의 Perforce 서버에 변경사항이 커밋될 때마다 일치하는 바이너리를 AWS S3에 업로드하고 해당 파일에 대한 매니페스트를 해당 파일 다운로드에 사용할 수 있는 Git repository에 커밋합니다. GitSync 툴은 저장소의 루트에서 Setup.bat 파일을 실행하여 설치한 Git 후크를 통해 새 커밋이 체크아웃될 때마다 매니페스트를 사용하여 해당 파일을 얻고 압축을 풉니다.
GitSync의 주요 설계 목표 중 하나는 많은 언리얼 엔진 개발자들을 지원할 수 있는 활성 서버를 유지할 필요 없이 바이너리 데이터의 호스팅을 검증되었으며 확장 가능한 타사 스토리지 서비스(AWS S3)에 오프로드하는 것입니다. 따라서 Git에서 사용되는 콘텐츠 어드레싱의 개념은 유지하되, 보다 효율적으로 다운로드할 수 있도록 콘텐츠 어드레싱 페이로드를 비결정론적 패키지로 패킹했습니다. 업로드 시 휴리스틱 기법을 사용하여 데이터 다운로드에 기존 패키지를 재사용할지, 또는 비용이 많이 드는 수집 작업을 방지하기 위해 새 패키지로 다시 패킹할지 여부를 결정합니다.
클라이언트는 고유 식별 SHA1 해시를 통해 보유할 수 있는 가용 로컬 캐시 데이터를 사용하여 Git과 같은 머클 트리 구조의 데이터 모델링을 계속할 수 있으며, 요청될 것으로 예상되는 블롭 간 일관성을 최적화하기 위해 정렬된 사전 제작 스태틱 다운로드 패키지에 데이터를 넣음으로써 클라이언트로 전송되는 데이터를 협상하는 데 있어서의 번거로움과 서버 측 계산 부하가 줄어듭니다.
이 모델은 필요시 포인트 읽기를 수용하는 동시에 스트리밍 읽기 및 쓰기에 맞게 최적화됩니다.
블롭
호드의 블롭에는 다음과 같은 어트리뷰트가 있습니다(BlobData 클래스 참고).
-
타입(Type): GUID 및 인티저 버전 번호로 나타내며, 특정 시리얼라이제이션 포맷을 보유할 수도 있지만 데이터는 동일한 페이로드 간에 구별하는 데 사용됩니다.
-
페이로드(Payload): 바이트 배열입니다. 블롭은 메모리로 완전히 읽히는 용도이므로, 페이로드는 일반적으로 몇백 KB로 제한됩니다. 대량의 페이로드는 유틸리티 라이브러리를 통해 스태틱 또는 콘텐츠 정의 청크를 사용하여 작은 블롭으로 분할할 수 있습니다.
-
레퍼런스(References): 다른 블롭에 대한 레퍼런스 세트입니다.
블롭에 대한 레퍼런스는 일반적으로 IBlobHandle 인스턴스를 사용하여 메모리에서 조작합니다. 스토리지로 플러시한 후에는 블롭 핸들을 스토리지 시스템에서 할당한 불투명한 구현 정의 스트링 식별자인 BlobLocator 로 변환하거나 BlobLocator 에서 변환할 수 있습니다.
호드는 IBlobWriter 인터페이스를 통해 블롭이 기본 스토리지 백엔드로 시리얼라이즈되는 방식을 추상화합니다. 프로그래머는 블롭을 시리얼라이즈할 버퍼를 요청하고, 데이터 및 그 레퍼런스를 작성하며, 향후 어느 시점에서든 얻을 수 있도록 IBlobHandle 을 다시 구합니다. 구현은 데이터 저장 방식을 결정하기 위해 남겨 두며, 필요시 데이터 압축, 패킹, 버퍼링, 업로드를 구현합니다.
다수의 IBlobWriter 인스턴스를 생성하여 관련된 블롭의 별도 스트림을 작성할 수 있습니다.
레퍼런스 및 에일리어스
레퍼런스와 에일리어스는 스토리지 시스템에 엔트리 포인트를 제공합니다. 이 중 하나로 특정 블롭에 사용자 정의 이름을 할당하여 나중에 얻을 수 있습니다.
-
레퍼런스(Ref) 는 블롭 스토어에 대한 강한 레퍼런스로, 가비지 컬렉터의 루트 역할을 합니다. 레퍼런스는 고정된 시간에 만료되도록 설정하거나, 특정 기간 동안 얻어지지 않으면 만료되도록 설정할 수 있습니다. 이는 캐시 구현에 유용합니다.
-
에일리어스(Alias) 는 블롭에 대한 약한 레퍼런스입니다. 이름이 동일한 여러 에일리어스가 존재할 수 있으며, 사용자는 특정한 에일리어스가 있는 하나 이상의 블롭을 쿼리할 수 있습니다. 에일리어스에는 연관된 사용자별 등급이 있으며, 컨슈머는 등급에 따라 정렬된 에일리어스를 쿼리할 수 있습니다.
콘텐츠 어드레싱
호드는 콘텐츠 어드레싱을 지원하는 방식으로 블롭을 모델링합니다. 해시는 BlobLocator 스트링을 통해 직접적으로 노출되지 않지만, 레퍼런스 배열에 일치하는 항목이 있는 블롭의 페이로드로 인코딩할 수 있습니다.
레퍼런스는 블롭 페이로드와 별도로 저장되므로, BlobLocator 를 통해 저장된 고유 식별자는 페이로드의 해시에 영향을 미치지 않습니다.
구현은 주로 블롭 데이터 해싱에 IoHash 를 사용하지만(잘린 20바이트 Blake 3 해시), 페이로드의 해시 인코딩을 스토리지 시스템의 레퍼런스에서 분리하면 대신 다른 해싱 알고리즘을 사용할 수 있습니다. 기본 스토리지 시스템은 블롭 트리의 토폴로지를 추론할 수 있는 한편, 다양한 해싱 알고리즘을 계속 지원합니다.
IBlobRef 인터페이스는 기본 IBlobHandle 인터페이스를 타깃 블롭의 IoHash 로 확장합니다.
구현
이 섹션에서는 스토리지 시스템의 현재 구현을 자세히 설명하며, 이는 향후 출시 버전에서 변경될 수 있습니다.
레이어
스토리지 시스템은 다음과 같은 여러 레이어를 통해 구현됩니다.
-
C# 시리얼라이제이션 라이브러리(
BlobSerializer,BlobConverter등) -
논리적 스토리지 모델은 스토리지 시스템과 상호작용하기 위한 주요 수단인
IStorageClient인터페이스를 통해 선언됩니다. 이 레이어에서 블롭은IBlobHandle오브젝트를 통해 조작됩니다.-
BundleStorageClient는IStorageClient의 표준 구현이며 블롭을 번들로 패킹합니다. -
KeyValueStorageClient는 개별 블롭을 기본IStorageBackend에 전달하는 클라이언트를 구현합니다.
-
-
물리적 스토리지 모델은 스토리지 서비스 구현에 대한 데이터 전송을 유선상으로 처리하는
IStorageBackend인터페이스를 통해 선언됩니다.-
HttpStorageBackend는 HTTP를 통해 호드 서버에 데이터를 업로드합니다. -
FileStorageBackend는 디스크상의 파일에 데이터를 직접 씁니다. -
MemoryStorageBackend는 메모리에 데이터를 저장합니다.
-
-
벌크 데이터 스토어는 저수준 스토리지 서비스와 상호작용하는
IObjectStore인터페이스를 통해 선언됩니다.-
FileObjectStore는 디스크상의 파일에 데이터를 씁니다. -
AwsObjectStore는 AWS S3에서 데이터를 읽고 씁니다. -
AzureObjectStore는 Azure 블롭 스토어에서 데이터를 읽고 씁니다.
-
번들
블롭은 일반적인 용도의 스토리지 프리미티브로 사용하도록 설계되었으므로, 에픽은 몇 바이트부터 몇백 킬로바이트까지 다양한 블롭 타입을 효율적으로 수용하기 위해 노력하고 있습니다(대량의 데이터 스트림은 고정된 바운더리를 따라서 또는 콘텐츠 정의 슬라이싱을 사용하여 작은 청크로 분할할 수 있습니다).
블롭은 기본 오브젝트 스토어에서 스토리지용 번들로 함께 패킹됩니다.
번들의 구현 및 스토리지 시스템 내 사용은 대부분 사용자 코드에서 숨겨지지만, 블롭 스트림이 스토리지에 어떻게 작성되는지 알면 액세스 패턴을 추론하는 데 도움이 될 수 있습니다.
각 번들은 일련의 압축된 패킷으로 구성되어 있으며, 패킷마다 여러 블롭이 포함될 수 있습니다. 각 패킷은 독립적이므로 번들 데이터의 단일 연속 범위 지정 읽기에서 디코딩할 수 있습니다.
로케이터
로케이터의 일반적인 형식은 다음과 같습니다.
[path]#pkt=[offset],[length]&exp=[index]
[path]: 기본 오브젝트 스토어 내 오브젝트에 대한 경로입니다.[offset]및[length]: 번들 내 압축된 패킷 데이터의 바이트 범위입니다.[index]: 패킷 내 익스포트된 블롭의 인덱스입니다.