Programming/MSA

Netflix ) Netflix’s Key-Value Data Abstraction Layer

armyost 2025. 1. 13. 00:32
728x90

넷플릭스는 Key-Value String Data의 영속성 Layer로 어떠한것을 사용했는지, 어떤 비즈니즈 요구사항에 적용했는지 리서치 해보았다.

 

관련 포스팅

https://netflixtechblog.com/introducing-netflixs-key-value-data-abstraction-layer-1ea8a0a11b30

 

Introducing Netflix’s Key-Value Data Abstraction Layer

Vidhya Arvind, Rajasekhar Ummadisetty, Joey Lynch, Vinay Chella

netflixtechblog.com

 

https://netflixtechblog.com/introducing-netflix-timeseries-data-abstraction-layer-31552f6326f8

 

Introducing Netflix’s TimeSeries Data Abstraction Layer

By Rajiv Shringi, Vinay Chella, Kaidan Fullerton, Oleksii Tkachuk, Joey Lynch

netflixtechblog.com

 

 

The Key-Value Service


KV 데이터 추상화 서비스는 분산 데이터베이스에서 데이터 액세스 패턴과 관련하여 우리가 직면한 지속적인 과제를 해결하기 위해 도입되었습니다. 우리의 목표는 가장 간단한 해시맵에서 더 복잡한 데이터 구조에 이르기까지 다양한 사용 사례를 처리할 수 있는 다재다능하고 효율적인 데이터 저장 솔루션을 구축하는 것이었으며, 동시에 높은 가용성, 조정 가능한 일관성 및 낮은 대기 시간을 보장하는 것이었습니다.

 

Data Model

핵심적으로 KV 추상화는 2단계 맵 아키텍처를 중심으로 구축되었습니다. 첫 번째 수준은 해시된 문자열 ID(기본 키)이고 두 번째 수준은 키-값 바이트 쌍의 정렬된 맵입니다. 이 모델은 유연성과 효율성의 균형을 유지하면서 단순하고 복잡한 데이터 모델을 모두 지원합니다.

HashMap<String, SortedMap<Bytes, Bytes>>

 

구조화된 레코드 또는 시간 순서가 지정된 이벤트와 같은 복잡한 데이터 모델의 경우 이 2단계 접근 방식은 계층 구조를 효과적으로 처리하여 관련 데이터를 함께 검색할 수 있습니다. 더 간단한 사용 사례의 경우 단순 키-값 맵(예: id → {"" → value}) 또는 명명된 세트(예: id → {key → ""})를 나타냅니다. 이러한 적응성을 통해 KV 추상화를 수백 가지의 다양한 사용 사례에 사용할 수 있으므로 Netflix와 같은 대규모 인프라에서 단순하고 복잡한 데이터 모델을 모두 관리하기 위한 다목적 솔루션이 됩니다.

 

The corresponding Data Definition Language (DDL) for this structure in Cassandra is:

CREATE TABLE IF NOT EXISTS <ns>.<table> (
  id             text,
  key            blob,
  value          blob,
  value_metadata blob,

PRIMARY KEY (id, key))
WITH CLUSTERING ORDER BY (key <ASC|DESC>)

 

 

Namespace: Logical and Physical Configuration


네임스페이스는 데이터가 저장되는 위치와 방법을 정의하여 기본 스토리지 시스템을 추상화하는 동시에 논리적 및 물리적 분리를 제공합니다. 또한 일관성 또는 대기 시간 목표와 같은 액세스 패턴의 중앙 구성 역할도 합니다. 각 네임스페이스는 Cassandra, EVCache 또는 여러 조합 등 다양한 백엔드를 사용할 수 있습니다. 이러한 유연성을 통해 당사의 데이터 플랫폼은 성능, 내구성 및 일관성 요구 사항에 따라 다양한 사용 사례를 가장 적합한 스토리지 시스템으로 라우팅할 수 있습니다. 개발자는 데이터베이스 솔루션이 아닌 데이터 문제만 제공합니다!

이 예제 구성에서 ngsegment 네임스페이스는 Cassandra 클러스터와 EVCache 캐싱 계층 모두에서 지원되므로 내구성이 뛰어난 영구 스토리지와 지연 시간이 짧은 지점 읽기가 가능합니다.

 

stence_configuration":[                                                   
  {                                                                           
    "id":"PRIMARY_STORAGE",                                                 
    "physical_storage": {                                                    
      "type":"CASSANDRA",                                                 
      "cluster":"cassandra_kv_ngsegment",                                
      "dataset":"ngsegment",                                             
      "table":"ngsegment",                                               
      "regions": ["us-east-1"],
      "config": {
        "consistency_scope": "LOCAL",
        "consistency_target": "READ_YOUR_WRITES"
      }                                            
    }                                                                       
  },                                                                          
  {                                                                           
    "id":"CACHE",                                                           
    "physical_storage": {                                                    
      "type":"CACHE",                                                     
      "cluster":"evcache_kv_ngsegment"                                   
     },                                                                      
     "config": {                                                              
       "default_cache_ttl": 180s                                             
     }                                                                       
  }                                                                           
]

 

 

Key APIs of the KV Abstraction

To support diverse use-cases, the KV abstraction provides four basic CRUD APIs:

 

PutItems — Write one or more Items to a Record

The PutItems API is an upsert operation, it can insert new data or update existing data in the two-level map structure.

message PutItemRequest (
  IdempotencyToken idempotency_token,
  string           namespace, 
  string           id, 
  List<Item>       items
)

 

보시다시피 요청에는 동일한 쓰기 재시도가 안전한지 확인하기 위한 네임스페이스, 레코드 ID, 하나 이상의 항목 및 멱등성 토큰이 포함됩니다. 청크 데이터는 청크를 스테이징한 다음 적절한 메타데이터(예: 청크 수)와 함께 커밋하여 작성할 수 있습니다.

 

GetItems — Read one or more Items from a Record

GetItemsAPI는 ID, 조건자 및 선택 메커니즘을 사용하여 데이터를 가져오는 구조화되고 적응적인 방법을 제공합니다. 이 접근 방식은 성능과 안정성을 위해 엄격한 SLO(서비스 수준 목표)를 충족하면서 대량의 데이터를 검색해야 하는 필요성의 균형을 유지합니다.

message GetItemsRequest (
  String              namespace,
  String              id,
  Predicate           predicate,
  Selection           selection,
  Map<String, Struct> signals
)

 

GetItemsRequest에는 몇 가지 주요 매개변수가 포함되어 있습니다.

- 네임스페이스: 논리적 데이터세트 또는 테이블을 지정합니다.
- Id: 최상위 HashMap의 항목을 식별합니다.
- 조건자: 일치하는 항목을 필터링하고 모든 항목(match_all), 특정 항목(match_keys) 또는 범위(match_range)를 검색할 수 있습니다.
- 선택: 페이지 매기기를 위한 page_size_bytes, 페이지 전체의 총 항목 수를 제한하기 위한 item_limit, 응답에서 큰 값을 포함하거나 제외하기 위한 포함/제외 등 반환된 응답을 좁힙니다.
- 신호: 클라이언트 압축 또는 청크 지원과 같은 클라이언트 기능을 나타내는 대역 내 신호를 제공합니다.

 

The GetItemResponse message contains the matching data:

message GetItemResponse (
  List<Item>       items,
  Optional<String> next_page_token
)

 

- 항목: 요청에 정의된 조건자 및 선택 항목을 기반으로 검색된 항목 목록입니다.
- 다음 페이지 토큰: 필요한 경우 후속 읽기 위치를 나타내는 선택적 토큰으로, 여러 요청에 걸쳐 대규모 데이터 세트를 처리하는 데 필수적입니다. 페이지 매김은 특히 일반적인 응답 크기 제한을 초과할 수 있는 대규모 데이터 세트를 처리할 때 데이터 검색을 효율적으로 관리하는 데 중요한 구성 요소입니다.

 

DeleteItems — Delete one or more Items from a Record

DeleteItems API는 멱등성을 지원하는 동시에 레코드 수준, 항목 수준 및 범위 삭제를 포함하여 데이터를 제거하기 위한 유연한 옵션을 제공합니다.

message DeleteItemsRequest (
  IdempotencyToken idempotency_token,
  String           namespace,
  String           id,
  Predicate        predicate
)

 

GetItems API와 마찬가지로 Predicate를 사용하면 하나 이상의 항목을 한 번에 처리할 수 있습니다.

- 레코드 수준 삭제(match_all): 레코드의 항목 수에 관계없이 일정한 대기 시간으로 전체 레코드를 제거합니다.
- 항목 범위 삭제(match_range): 레코드 내의 항목 범위를 삭제합니다. "n-최신" 유지 또는 접두사 경로 삭제에 유용합니다.
- 항목 수준 삭제(match_keys): 하나 이상의 개별 항목을 삭제합니다.

 

Cassandra와 같은 일부 스토리지 엔진(실제 삭제를 연기하는 모든 저장소)은 삭제 표시 및 압축 오버헤드로 인해 대량의 삭제로 인해 어려움을 겪습니다. 키-값은 레코드 및 범위 삭제를 모두 최적화하여 작업에 대한 단일 삭제 표시를 생성합니다. 삭제 정보 및 삭제 표시에서 삭제 표시에 대해 자세히 알아볼 수 있습니다.

항목 수준 삭제는 많은 삭제 표시를 생성하지만 KV는 지터가 있는 TTL 기반 삭제를 통해 스토리지 엔진 복잡성을 숨깁니다. 즉시 삭제하는 대신, 항목 메타데이터는 시차적 삭제에 적용된 무작위 지터링 TTL을 사용하여 만료된 것으로 업데이트됩니다. 이 기술은 읽기 페이지 매김 보호를 유지합니다. 이것이 문제를 완전히 해결하지는 못하지만 로드 스파이크를 줄이고 압축이 따라잡는 동안 일관된 성능을 유지하는 데 도움이 됩니다. 이러한 전략은 삭제의 영향을 최소화하여 시스템 성능을 유지하고, 읽기 오버헤드를 줄이고, SLO를 충족하는 데 도움이 됩니다.

 

 

Complex Mutate and Scan APIs

단일 레코드에 대한 간단한 CRUD 외에도 KV는 MutateItems 및 ScanItems API를 통해 복잡한 다중 항목 및 다중 레코드 변형과 스캔을 지원합니다. PutItems는 청크 프로토콜을 통해 단일 항목 내에서 대규모 Blob 데이터의 원자성 쓰기도 지원합니다. 이러한 복잡한 API는 예측 가능한 선형 짧은 지연 시간을 보장하기 위해 신중한 고려가 필요하며 향후 게시물에서 구현에 대한 세부 정보를 공유할 것입니다.

 

데이터 무결성을 보장하기 위해 PutItems 및 DeleteItems API는 멱등성 토큰을 사용합니다. 이 토큰은 각 변형 작업을 고유하게 식별하고 지연 시간으로 인해 헤징되거나 재시도되는 경우에도 작업이 논리적으로 순서대로 실행되도록 보장합니다. 이는 요청의 올바른 순서와 중복 제거를 보장하는 것이 중요한 Cassandra와 같은 최종 쓰기 승리 데이터베이스에서 특히 중요합니다.

키-값 추상화에서 멱등성 토큰에는 생성 타임스탬프와 임의 nonce 토큰이 포함됩니다. 변형을 중복 제거하기 위해 스토리지 엔진을 지원하려면 둘 중 하나 또는 둘 다 필요할 수 있습니다.

 

Netflix에서는 특히 네트워크 지연이 서버 측 토큰 생성에 영향을 미칠 수 있는 환경에서 신뢰성 때문에 클라이언트 생성 단조 토큰을 선호합니다. 이는 클라이언트가 제공한 단조로운 Generation_time 타임스탬프와 128비트 무작위 UUID 토큰을 결합합니다. 시계 기반 토큰 생성은 시계 왜곡으로 인해 문제가 발생할 수 있지만 EC2 Nitro 인스턴스에 대한 테스트에서는 드리프트가 최소화되는 것으로 나타났습니다(1밀리초 미만). 더 강력한 순서가 필요한 경우에는 Zookeeper와 같은 도구를 사용하여 지역적으로 고유한 토큰을 생성하거나 트랜잭션 ID와 같은 전역적으로 고유한 토큰을 사용할 수 있습니다.

 

 

Handling Large Data through Chunking

또한 Key-Value는 기존 키-값 저장소의 일반적인 과제인 대규모 Blob을 효율적으로 처리하도록 설계되었습니다. 데이터베이스는 키 또는 파티션별로 저장할 수 있는 데이터 양에 제한이 있는 경우가 많습니다. 이러한 제약을 해결하기 위해 KV는 투명한 청크를 사용하여 대용량 데이터를 효율적으로 관리합니다.

1MiB보다 작은 항목의 경우 데이터는 기본 지원 스토리지(예: Cassandra)에 직접 저장되어 빠르고 효율적인 액세스를 보장합니다. 그러나 더 큰 항목의 경우 ID, 키 및 메타데이터만 기본 저장소에 저장되고 실제 데이터는 더 작은 청크로 분할되어 청크 저장소에 별도로 저장됩니다. 이 청크 저장소는 Cassandra일 수도 있지만 큰 값을 처리하는 데 최적화된 다른 파티셔닝 체계를 사용합니다. 멱등성 토큰은 이러한 모든 쓰기를 하나의 원자적 작업으로 묶습니다.

큰 항목을 여러 개의 청크로 분할함으로써 대기 시간이 데이터 크기에 따라 선형적으로 확장되도록 하여 시스템을 예측 가능하고 효율적으로 만듭니다. 향후 블로그 게시물에서는 복잡성과 최적화 전략을 포함하여 청킹 아키텍처에 대해 더 자세히 설명할 것입니다.

 

 

Client-Side Compression

KV 추상화는 클라이언트 측 페이로드 압축을 활용하여 특히 대규모 데이터 전송의 성능을 최적화합니다. 많은 데이터베이스가 서버측 압축을 제공하지만 클라이언트측에서 압축을 처리하면 값비싼 서버 CPU 사용량, 네트워크 대역폭 및 디스크 I/O가 줄어듭니다. Netflix의 검색을 강화하는 데 도움이 되는 배포 중 하나에서는 클라이언트 측 압축을 활성화하여 페이로드 크기를 75% 줄여 비용 효율성을 크게 향상시켰습니다.

 

Smarter Pagination

우리는 예측 가능한 작업 SLO를 제공할 수 있도록 항목 수 대신 응답 페이지당 제한으로 페이로드 크기(바이트)를 선택했습니다. 예를 들어 2MiB 페이지 읽기에 대해 한 자리 밀리초 SLO를 제공할 수 있습니다. 반대로, 페이지당 항목 수를 제한으로 사용하면 항목 크기의 상당한 변화로 인해 예측할 수 없는 지연 시간이 발생할 수 있습니다. 페이지당 10개 항목을 요청하면 각 항목이 1KiB와 1MiB인 경우 지연 시간이 크게 달라질 수 있습니다.

바이트 기반 페이지 매김을 지원하는 백업 저장소가 거의 없기 때문에 바이트를 제한으로 사용하면 문제가 발생합니다. 대부분의 데이터 저장소는 결과 수를 사용합니다. DynamoDB 및 Cassandra는 항목 또는 행 수로 제한됩니다. 이 문제를 해결하기 위해 백업 저장소에 대한 초기 쿼리에 정적 제한을 사용하고, 이 제한으로 쿼리하고, 결과를 처리합니다. 바이트 제한을 충족하기 위해 더 많은 데이터가 필요한 경우 제한이 충족될 때까지 추가 쿼리가 실행되고 초과 결과는 삭제되고 페이지 토큰이 생성됩니다.

이러한 정적 제한은 비효율성을 초래할 수 있으며, 결과의 하나의 큰 항목으로 인해 많은 결과가 삭제될 수 있는 반면, 작은 항목은 페이지를 채우는 데 여러 번의 반복이 필요할 수 있어 읽기 증폭이 발생할 수 있습니다. 이러한 문제를 완화하기 위해 우리는 관찰된 데이터를 기반으로 제한을 동적으로 조정하는 적응형 페이지 매김을 구현했습니다.

 

 

Adaptive Pagination

초기 요청이 이루어지면 스토리지 엔진에서 쿼리가 실행되고 결과가 검색됩니다. 소비자가 이러한 결과를 처리할 때 시스템은 소비된 항목 수와 사용된 총 크기를 추적합니다. 이 데이터는 페이지 토큰에 저장되는 대략적인 항목 크기를 계산하는 데 도움이 됩니다. 후속 페이지 요청의 경우 이 저장된 정보를 통해 서버는 기본 스토리지에 적절한 제한을 적용하여 불필요한 작업을 줄이고 읽기 증폭을 최소화할 수 있습니다.

이 방법은 후속 페이지 요청에 효과적이지만 초기 요청에서는 어떻게 되나요? 페이지 토큰에 항목 크기 정보를 저장하는 것 외에도 서버는 지정된 네임스페이스에 대한 평균 항목 크기를 추정하고 이를 로컬로 캐시합니다. 이 캐시된 추정치는 서버가 초기 요청에 대해 백업 저장소에 대해 보다 최적의 제한을 설정하여 효율성을 높이는 데 도움이 됩니다. 서버는 정확성을 유지하기 위해 최신 쿼리 패턴이나 기타 요인을 기반으로 이 제한을 지속적으로 조정합니다. 후속 페이지의 경우 서버는 캐시된 데이터와 페이지 토큰의 정보를 모두 사용하여 제한을 미세 조정합니다.

 

 

 

적응형 페이지 매김 외에도 요청 처리가 요청의 대기 시간 SLO를 초과할 위험이 있음을 서버가 감지하는 경우 조기에 응답을 보내는 메커니즘이 마련되어 있습니다.

예를 들어, 클라이언트가 페이지당 제한이 2MiB이고 최대 엔드투엔드 대기 시간 제한이 500ms인 GetItems 요청을 제출한다고 가정해 보겠습니다. 이 요청을 처리하는 동안 서버는 백업 저장소에서 데이터를 검색합니다. 이 특정 레코드에는 수천 개의 작은 항목이 있으므로 전체 데이터 페이지를 수집하는 데 일반적으로 500ms SLO보다 오래 걸립니다. 이 경우 클라이언트는 SLO 위반 오류를 수신하게 되어 예외가 없더라도 요청이 실패하게 됩니다. 이를 방지하기 위해 서버는 데이터를 가져오는 동안 경과 시간을 추적합니다. 더 많은 데이터를 계속 검색하면 SLO를 위반할 수 있다고 판단되면 서버는 추가 결과 처리를 중지하고 페이지 매김 토큰이 포함된 응답을 반환합니다.

 

이 접근 방식을 사용하면 전체 페이지 크기가 충족되지 않더라도 SLO 내에서 요청이 처리되므로 클라이언트에게 예측 가능한 진행 상황이 제공됩니다. 또한 클라이언트가 적절한 기한을 가진 gRPC 서버인 경우 클라이언트는 추가 요청을 발행하지 않을 만큼 똑똑하므로 불필요한 작업이 줄어듭니다.

 


 

Netflix’s TimeSeries Data Abstraction Layer

 

Challenges


Netflix에서는 비디오 재생 이벤트, 자산 노출 또는 복잡한 마이크로 서비스 네트워크 활동과 같은 사용자 상호 작용에서 시간 데이터가 지속적으로 생성되고 활용됩니다. 귀중한 통찰력을 추출하기 위해 이 데이터를 대규모로 효과적으로 관리하는 것은 최적의 사용자 경험과 시스템 안정성을 보장하는 데 매우 중요합니다.

그러나 이러한 데이터를 저장하고 쿼리하는 데는 다음과 같은 고유한 과제가 있습니다.

- 높은 처리량: 고가용성을 유지하면서 초당 최대 1,000만 개의 쓰기를 관리합니다.
- 대규모 데이터 세트의 효율적인 쿼리: 페타바이트 규모의 데이터를 저장하는 동시에 기본 키 읽기가 낮은 두 자릿수 밀리초 내에 결과를 반환하도록 보장하고 여러 보조 속성에 대한 검색 및 집계를 지원합니다.
- 전역 읽기 및 쓰기: 조정 가능한 일관성 모델을 통해 전 세계 어디에서나 읽기 및 쓰기 작업을 촉진합니다.
- 조정 가능한 구성: 보존 및 일관성과 같은 다양한 데이터 세트 측면을 조정하는 옵션과 함께 단일 테넌트 또는 다중 테넌트 데이터 저장소에서 데이터 세트를 분할하는 기능을 제공합니다.
- 급증하는 트래픽 처리: 새로운 콘텐츠 출시 또는 지역 장애 조치와 같이 수요가 많은 이벤트 중에 상당한 트래픽 급증을 관리합니다.
- 비용 효율성: 바이트당 및 작업당 비용을 줄여 장기 보존을 최적화하는 동시에 Netflix의 경우 수백만 달러에 달할 수 있는 인프라 비용을 최소화합니다.

 

 

TimeSeries Abstraction


TimeSeries Abstraction은 이러한 요구 사항을 충족하기 위해 개발되었으며 다음과 같은 핵심 설계 원칙을 기반으로 구축되었습니다.

- 분할된 데이터: 데이터는 폭주하는 워크로드를 효율적으로 관리하고 쿼리를 간소화하기 위해 이벤트 버킷팅 접근 방식과 결합된 고유한 임시 분할 전략을 사용하여 분할됩니다.
- 유연한 스토리지: 이 서비스는 Apache Cassandra 및 Elasticsearch를 포함한 다양한 스토리지 백엔드와 통합되도록 설계되어 Netflix가 특정 사용 사례 요구 사항에 따라 스토리지 솔루션을 맞춤 설정할 수 있습니다.
- 구성 가능성: TimeSeries는 각 데이터 세트에 대해 다양한 조정 가능한 옵션을 제공하여 다양한 사용 사례를 수용하는 데 필요한 유연성을 제공합니다.
- 확장성: 이 아키텍처는 수평 및 수직 확장을 모두 지원하므로 Netflix가 사용자 기반과 서비스를 확장함에 따라 시스템이 증가하는 처리량과 데이터 볼륨을 처리할 수 있습니다.
- 샤드 인프라: 데이터 게이트웨이 플랫폼을 활용하여 필요한 액세스 및 트래픽 격리를 갖춘 단일 테넌트 및/또는 다중 테넌트 인프라를 배포할 수 있습니다.
이 추상화의 다양한 측면을 살펴보겠습니다.

 

 

Data Model


우리는 이벤트에 대해 캡처하려는 모든 데이터를 캡슐화하는 동시에 효율적으로 쿼리할 수 있는 고유한 이벤트 데이터 모델을 따릅니다

 

 

추상화에서 가장 작은 데이터 단위부터 시작하여 계속해서 작업해 나가겠습니다.

- 이벤트 항목: 이벤트 항목은 사용자가 특정 이벤트에 대한 데이터를 저장하는 데 사용하는 키-값 쌍입니다. 예: {“device_type”: “ios”}.
- 이벤트: 이벤트는 하나 이상의 이벤트 항목을 체계적으로 모아 놓은 것입니다. 이벤트는 특정 시점에 발생하며 클라이언트가 생성한 타임스탬프와 이벤트 식별자(예: UUID)로 식별됩니다. event_time과 event_id의 이러한 조합은 이벤트에 대한 고유한 멱등성 키의 일부를 형성하므로 사용자가 안전하게 요청을 재시도할 수 있습니다.
- 시계열 ID: time_series_id는 데이터 세트의 보존 기간 동안 하나 이상의 이벤트 모음입니다. 예를 들어, device_id는 보존 기간 동안 특정 장치에서 발생하는 모든 이벤트를 저장합니다. 모든 이벤트는 변경할 수 없으며 TimeSeries 서비스는 지정된 시계열 ID에만 이벤트를 추가합니다.
- 네임스페이스: 네임스페이스는 전체 시계열 데이터 세트를 나타내는 시계열 ID 및 이벤트 데이터의 모음입니다. 사용자는 각 사용 사례에 대해 하나 이상의 네임스페이스를 만들 수 있습니다. 추상화는 네임스페이스 수준에서 다양한 조정 가능 옵션을 적용합니다. 이에 대해서는 서비스의 제어 플레인을 탐색할 때 자세히 논의하겠습니다.

 

 

 

API


The abstraction provides the following APIs to interact with the event data.

- WriteEventRecordsSync: 이 끝점은 일련의 이벤트를 작성하고 내구성 승인을 클라이언트에 다시 보냅니다. 사용자가 내구성 보장을 요구하는 경우에 사용됩니다.

- WriteEventRecords: 이는 위 엔드포인트의 실행 후 잊어버리는 버전입니다. 내구성 승인 없이 일련의 이벤트를 대기열에 추가합니다. 이는 사용자가 처리량에 더 관심을 갖고 약간의 데이터 손실을 허용할 수 있는 로깅 또는 추적과 같은 경우에 사용됩니다.

 

- ReadEventRecords: 네임스페이스, timeSeriesId, timeInterval 및 선택적 eventFilters의 조합이 주어지면 이 엔드포인트는 짧은 지연 시간으로 event_time을 기준으로 내림차순으로 정렬되어 일치하는 모든 이벤트를 반환합니다.

 

- SearchEventRecords: 검색 기준과 시간 간격이 주어지면 이 엔드포인트는 일치하는 모든 이벤트를 반환합니다. 이러한 사용 사례는 최종적 일관된 읽기에 적합합니다.

 

- AggregateEventRecords: 검색 기준 및 집계 모드(예: DistinctAggregation)가 주어지면 이 엔드포인트는 지정된 시간 간격 내에 지정된 집계를 수행합니다. 검색 엔드포인트와 유사하게 사용자는 최종 일관성과 잠재적으로 더 높은 대기 시간(초)을 허용할 수 있습니다.

 

 

Storage Layer

 

TimeSeries의 스토리지 계층은 기본 데이터 저장소와 선택적 인덱스 데이터 저장소로 구성됩니다. 기본 데이터 저장소는 쓰기 중 데이터 내구성을 보장하고 기본 읽기 작업에 사용되는 반면, 인덱스 데이터 저장소는 검색 및 집계 작업에 사용됩니다. Netflix에서는 처리량이 많은 시나리오에서 내구성 있는 데이터를 저장하는 데 Apache Cassandra가 선호되는 반면, Elasticsearch는 인덱싱을 위해 선호되는 데이터 저장소입니다. 그러나 API에 대한 접근 방식과 유사하게 스토리지 계층은 이러한 특정 데이터 저장소와 긴밀하게 결합되지 않습니다. 대신, 이행해야 하는 스토리지 API 계약을 정의하여 필요에 따라 기본 데이터 저장소를 교체할 수 있는 유연성을 제공합니다.

 

 

Reading from the data table:

아래 그림은 여러 파티션에서 읽은 내용을 분산 수집하고 마지막에 결과 집합을 결합하여 최종 결과를 반환하는 방법을 개략적으로 보여줍니다.