Sitemap
Netflix TechBlog

Learn about Netflix’s world class engineering efforts, company culture, product developments and more.

High-Throughput Graph Abstraction at Netflix: Part INetflix 的高吞吐量图抽象:第一部分

Netflix Technology Blog
Netflix Technology BlogNetflix 技术博客
13 min read13 分钟阅读Feb 9, 20262026 年 2 月 9 日

--

收听

By Oleksii Tkachuk, Kartik Sathyanarayanan, Rajiv Shringi作者:Oleksii Tkachuk、Kartik Sathyanarayanan、Rajiv Shringi

Introduction引言

Netflix has a diverse range of graph use cases, each serving specific business needs with unique functionality and performance requirements. These use cases fall into two broad categories:Netflix 拥有多种多样的图使用场景,每种场景都服务于特定的业务需求,具有独特的功能和性能要求。这些使用场景分为两大类:

  1. OLAP: These use cases typically involve open-ended and algorithmic exploration of large graph datasets. They often utilize industry-standard models and languages such as RDF with SPARQL, Property Graphs with Gremlin or openCypher, and even SQL. The primary focus in these situations is in-depth analysis, rather than achieving high throughput and low latency.OLAP:这些使用场景通常涉及对大型图数据集进行开放式和算法探索。它们通常使用行业标准模型和语言,例如带有 SPARQL 的 RDF、带有 Gremlin 或 openCypher 的属性图,甚至 SQL。这些情况下的主要关注点是深入分析,而不是实现高吞吐量和低延迟。
  2. OLTP: These use cases require extremely high throughput — up to millions of operations per second — while delivering traversal results within milliseconds. Achieving such a level of performance often requires making trade-offs, which can include accepting eventual consistency or restricting query complexity. For example, the service can demand a specified starting point for traversals and enforce a maximum traversal depth. Such use cases are often directly tied to streaming or user experiences and demand high global availability.OLTP:这些使用场景需要极高的吞吐量——每秒高达数百万次操作——同时在毫秒内提供遍历结果。要达到这样的性能水平通常需要做出权衡,这可能包括接受最终一致性或限制查询复杂性。例如,服务可以要求指定遍历的起点并强制执行最大遍历深度。此类使用场景通常直接与流媒体或用户体验相关,并要求高全局可用性。

Netflix’s Graph Abstraction was designed specifically for this second category of use cases. As of this writing, the abstraction is handling close to 10 million operations per second across 650 TB of graph datasets with low latency and cost efficiency.Netflix 的图抽象正是为第二类使用场景设计的。截至撰写本文时,该抽象正在处理近每秒 1000 万次操作,覆盖 650 TB 的图数据集,且具有低延迟和成本效益。

This post is the first in a multi-part series that explores the Graph Abstraction architecture in depth. We’ll cover how the abstraction indexes data for real-time and historical views, manages strongly typed graphs, performs efficient traversals, and integrates with the Netflix Big Data ecosystem.本文是一个多部分系列的第一篇,深入探讨图抽象架构。我们将介绍抽象如何为实时和历史视图索引数据、管理强类型图、执行高效遍历,以及与 Netflix 大数据生态系统集成。

Usage at Netflix在 Netflix 的使用

From a business standpoint, the primary driver for developing the Graph Abstraction was internal demand for supporting several key use cases:从业务角度来看,开发图抽象的主要驱动力是内部对支持几个关键用例的需求:

  • Real-Time Distributed Graph (RDG): A graph capturing dynamic relationships across entities and interactions throughout the Netflix ecosystem. You can learn more about the initial RDG implementation in this insightful blog post. This functionality has since been integrated into the Graph Abstraction.实时分布式图(RDG):一种捕获Netflix生态系统中跨实体和交互的动态关系的图。您可以在这篇富有洞察力的博客文章中了解有关初始RDG实现的更多信息。此功能现已集成到图抽象中。
  • Social Graph: A graph of social connections within Netflix Gaming, designed to boost user engagement.社交图:Netflix游戏中的社交关系图,旨在提高用户参与度。
  • Service Topology: A graph of all internal Netflix services, used for real-time and historical analysis to improve root cause analysis during incidents.服务拓扑:所有内部Netflix服务的图,用于实时和历史分析,以改进事件期间的根因分析。

Let’s examine the overall architecture of the Graph Abstraction and how it integrates with the Netflix Online Datastore ecosystem.让我们检查图抽象的整体架构以及它如何与Netflix在线数据存储生态系统集成。

Architecture架构

Instead of building the persistence and caching layers from scratch, we chose to build taller on top of existing Netflix data abstractions.我们没有从头开始构建持久化和缓存层,而是选择在现有Netflix数据抽象的基础上构建更高的层次。

Press enter or click to view image in full size按回车键或点击查看全尺寸图像

The Key-Value (KV) Abstraction stores the latest view of nodes and edges, serving as the real-time index for all queries. Optionally, users can plug-in the TimeSeries (TS) Abstraction if they are interested in a historical view of how the graph evolves over time. Additionally, we use EVCache to achieve low-millisecond latencies and are actively experimenting with more specialized caching layers to further improve performance. Finally, the Graph Abstraction integrates with the Data Gateway Control Plane to manage graph schemas and automate the provisioning, deletion, and configuration of datasets in both KV and TS.键值(KV)抽象存储节点和边的最新视图,作为所有查询的实时索引。可选地,如果用户对图随时间演变的历史视图感兴趣,他们可以插入时间序列(TS)抽象。此外,我们使用EVCache来实现低毫秒级延迟,并正在积极尝试更专门的缓存层以进一步提高性能。最后,图抽象与数据网关控制平面集成,以管理图模式并自动化KV和TS中数据集的配置、删除和配置。

Property Graph Model属性图模型

The Abstraction uses the Property Graph model to store its data. The graph consists of nodes and edges of various types, each with associated properties. These properties are strongly typed to enable efficient filtering and ensure consistent data exports. For semantic reasons, edges can be either unidirectional or bidirectional.抽象层使用属性图模型来存储其数据。该图由各种类型的节点和边组成,每个节点和边都有相关的属性。这些属性是强类型的,以便实现高效过滤并确保数据导出的一致性。出于语义原因,边可以是单向的或双向的。

Press enter or click to view image in full size

Namespaces命名空间

The Abstraction separates data into isolated units called “namespaces.” Each namespace is associated with a physical storage layer, as configured in the Data Gateway Control Plane, and can be deployed on either dedicated or shared hardware. The optimal, most cost-effective hardware configuration is determined by our provisioning automation, based on user-provided requirements such as throughput, latency, dataset size, and workload criticality. For more details on this topic, see this talk given by our stunning colleague Joey Lynch at AWS re:Invent.抽象层将数据分隔成称为“命名空间”的独立单元。每个命名空间都与一个物理存储层相关联,该存储层在数据网关控制平面中配置,并且可以部署在专用或共享硬件上。最佳、最具成本效益的硬件配置由我们的配置自动化根据用户提供的需求(如吞吐量、延迟、数据集大小和工作负载关键性)确定。有关此主题的更多详细信息,请参阅我们出色的同事Joey Lynch在AWS re:Invent上的演讲。

Graph Schema图模式

Each namespace is further associated with an explicit graph schema configured in the Control Plane. The graph schema defines node and edge types, allowed properties, permitted relationships, and directions.每个命名空间还与在控制平面中配置的显式图模式相关联。图模式定义了节点和边的类型、允许的属性、允许的关系以及方向。

Press enter or click to view image in full size

The Graph schema is implemented as a collection of edge mappings that describe the nature of the relationship between given node types.图模式实现为一系列边映射的集合,这些映射描述了给定节点类型之间关系的性质。

{
"edgeConfig": {
"edgeMappings": [
{
"edgeMappingKey": {
"fromNodeType": "account",
"edgeType": "owns",
"toNodeType": "profile"
},
"directionType": "UNIDIRECTIONAL"
},
{
"edgeMappingKey": {
"fromNodeType": "profile",
"edgeType": "linked_to",
"toNodeType": "device"
},
"directionType": "BIDIRECTIONAL"
}
]
}
}

Edge mappings are further extended with specification of property schema that consists of allowed property names and their type specification:边映射进一步扩展了属性模式的规范,该规范包括允许的属性名称及其类型说明:

{
"edgeMappingKey":{
"fromNodeType":"profile",
"edgeType":"linked_to",
"toNodeType":"device"
},
"propertySchema":{
"propertyMappings":[
{ "propertyKey":"registration_time", "propertyValueType":"TIMESTAMP" },
{ "propertyKey":"status", "propertyValueType":"STRING" }
]
}
}

The Abstraction servers load this schema on startup and build an in-memory metadata graph of possible relationships, enabling several key optimizations:抽象层服务器在启动时加载此模式,并构建一个可能关系的内存元数据图,从而实现几个关键优化:

  • Data Quality: The Abstraction rejects non-conforming nodes, edges, and properties during writes, ensuring high data quality and consistent exports.数据质量:抽象层在写入时拒绝不符合规范的节点、边和属性,确保高数据质量和一致的导出。
  • Query Planning: The Abstraction uses the schema to quickly construct the possible traversal paths the service should take to answer a given user query.查询规划:抽象层使用模式快速构建服务为回答给定用户查询而应采取的可能的遍历路径。
  • Deduplication of Traversed Edges: For bidirectional traversals on edges between the same node type, the schema helps avoid redundant processing by deduplicating traversed paths.遍历边的去重:对于同一节点类型之间的边上的双向遍历,模式通过去重遍历路径帮助避免冗余处理。
  • Eliminating Traversal paths: For a given user query, the Abstraction removes traversal paths associated with impossible relationships, as well as those where filters or property types are incompatible.消除遍历路径:对于给定的用户查询,抽象层移除与不可能关系相关的遍历路径,以及那些过滤器或属性类型不兼容的路径。

Further, the Abstraction servers periodically poll the schema from the Data Gateway Control Plane in order to keep it updated with user changes. Looking ahead, we plan to leverage the graph schema for additional improvements, such as:此外,抽象层服务器定期从数据网关控制平面轮询模式,以使其与用户更改保持同步。展望未来,我们计划利用图模式进行额外的改进,例如:

  • Minimizing Query Fanout: By using edge cardinality within edge mappings, we aim to select the most efficient traversal paths and minimize query fanout.最小化查询扇出:通过使用边映射中的边基数,我们旨在选择最有效的遍历路径并最小化查询扇出。
  • Improved Developer Experience: The schema will support generating a type-safe data access layer and enhance the Gremlin-like API with schema awareness.改进的开发者体验:该模式将支持生成类型安全的数据访问层,并通过模式感知增强类似Gremlin的API。

Next, let’s look at how this data is organized in a real-time index within the KV Abstraction.接下来,让我们看看这些数据如何在KV抽象层内的实时索引中组织。

Real-Time Index: Key-Value Storage实时索引:键值存储

Before we discuss how the data is organized into graph indexes, let’s discuss how KV organizes data within namespaces and provides idempotency guarantees:在讨论数据如何组织成图索引之前,我们先讨论KV如何在命名空间内组织数据并提供幂等性保证:

Press enter or click to view image in full size
  • Data partitioning: A namespace is associated with a table in the underlying storage layer. Within the table, data is partitioned into records by unique IDs, with each record holding multiple sorted items as key-value pairs. This structure effectively makes each namespace a map of sorted maps, providing flexibility for diverse access patterns.数据分区:命名空间与底层存储层中的表相关联。在表内,数据通过唯一ID分区为记录,每条记录包含多个排序的键值对项。这种结构有效地使每个命名空间成为排序映射的映射,为不同的访问模式提供了灵活性。
  • Idempotency: Writes to a given ID and key are idempotent, enabling request hedging and safe retries. The idempotency token contains a timestamp, which KV uses to enforce Last-Write-Wins (LWW) semantics at the storage layer.幂等性:对给定ID和键的写入是幂等的,支持请求对冲和安全重试。幂等令牌包含时间戳,KV使用该时间戳在存储层强制执行最后写入胜出(LWW)语义。

We use the KV as the underlying storage for all real-time graph indices on nodes and edges. For more on Netflix’s Key-Value Abstraction, see this excellent post published by our KeyValue team.我们使用KV作为所有节点和边实时图索引的底层存储。有关Netflix键值抽象的更多信息,请参阅我们的KeyValue团队发布的这篇优秀文章。

Node Storage节点存储

The two-tiered partitioning strategy works well for node storage. Each node type is isolated within its own KV namespace, which stores all the properties for nodes of that type.两层分区策略适用于节点存储。每种节点类型隔离在自己的KV命名空间中,该命名空间存储该类型节点的所有属性。

Press enter or click to view image in full size

This storage format enables several efficient access patterns for nodes:这种存储格式支持多种高效的节点访问模式:

  • Efficient reads: A given node and all its properties are fetched in a single partition lookup, achieving single-digit millisecond latency.高效读取:通过一次分区查找即可获取给定节点及其所有属性,实现个位数毫秒延迟。
  • Property selection pushdown: Target property keys are pushed down to the KV layer, reducing the amount of data fetched and further decreasing latencies and network overhead.属性选择下推:目标属性键被下推到KV层,减少获取的数据量,进一步降低延迟和网络开销。
  • Property filtering pushdown: Property keys and values can be efficiently filtered at the KV layer.属性过滤下推:属性键和值可以在KV层高效过滤。
  • Efficient exports: This model supports highly parallelized node exports by node type.高效导出:该模型支持按节点类型高度并行化的节点导出。

Edge Storage边存储

Links and Property Index链接和属性索引

Edges utilize two distinct types of indexes: one exclusively for the edge connections (links), and one for edge properties.边使用两种不同类型的索引:一种专门用于边连接(链接),另一种用于边属性。

The Edge links are arranged as an adjacency list mapping source nodes to their connected neighbors.边链接组织为邻接列表,将源节点映射到其连接的邻居。

Press enter or click to view image in full size

The Edge Property index stores information about properties of every edge.边属性索引存储每条边的属性信息。

Press enter or click to view image in full size

Separating edge links from their properties brings several benefits, but also introduces a key trade-off:将边链接与其属性分离带来了一些好处,但也引入了一个关键权衡:

Get Netflix Technology Blog’s stories in your inbox获取Netflix技术博客的故事到您的收件箱

Join Medium for free to get updates from this writer.免费加入 Medium,获取这位作者的最新动态。

Benefits:优势:

  • Efficient property upserts: Allows individual properties to be upserted over time without needing to read the entire property set for an edge.高效的属性更新:允许随时间单独更新属性,无需读取边的整个属性集。
  • Wide row prevention: Decoupling edge links from their properties prevents large partitions in databases like Cassandra, enabling efficient storage and low-latency reads — even for edges with millions of connections.防止宽行:将边链接与其属性解耦,可防止在 Cassandra 等数据库中形成大分区,从而实现高效存储和低延迟读取——即使对于拥有数百万连接的边也是如此。

Trade-off:权衡:

  • Non-atomic writes: Storing edges across multiple namespaces means that writes across these namespaces are not atomic. We’ll discuss how this is addressed in the Consistency Enforcement section.非原子写入:跨多个命名空间存储边意味着这些命名空间之间的写入不是原子的。我们将在一致性执行部分讨论如何解决这个问题。

Forward and Reverse Indexes正向和反向索引

Additionally, edge indexes are separated into forward and reverse indexes to support traversals in either direction. The illustration below shows an example of the reverse index counterpart for the links namespace shown above.此外,边索引分为正向和反向索引,以支持双向遍历。下图显示了上述链接命名空间的反向索引对应示例。

Press enter or click to view image in full size

To ensure consistent record identifiers when updating edge properties in either direction, the Abstraction lexicographically sorts and concatenates the source and destination node IDs to create a direction-agnostic identifier for property storage. This ensures that properties can be accessed or mutated in a single database call regardless of the direction specified in the request.为了在任一方向更新边属性时确保一致的记录标识符,Abstraction 按字典顺序排序并连接源节点和目标节点 ID,以创建用于属性存储的方向无关标识符。这确保了无论请求中指定的方向如何,都可以在单个数据库调用中访问或修改属性。

Press enter or click to view image in full size

This storage format enables several efficient access patterns:这种存储格式支持多种高效访问模式:

  • Point Reads: Given an edge id, all properties can be fetched in a single partition lookup on the properties index.点读取:给定边 ID,可以在属性索引上的单个分区查找中获取所有属性。
  • Range Reads: Given a source node, a range read on a partition in the links index can efficiently return all edges. Depending on the desired direction, the Abstraction can target the forward or reverse index.范围读取:给定源节点,对链接索引中分区的范围读取可以高效地返回所有边。根据所需方向,Abstraction 可以定位正向或反向索引。
  • Property Filtering: Properties are fetched only for the links that match the record or page limit criteria, minimizing the data exchanged over the network.属性过滤:仅获取与记录或页面限制条件匹配的链接的属性,从而最大限度地减少网络交换的数据量。
  • Sort Orders: By default, edge links are sorted lexicographically by their target node. To support fetching the latest connections, the Abstraction retrieves target edge links in memory, sorts them by their last-write time, and returns the results. In order to ensure optimal performance without exerting too much memory pressure, we aim to limit the number of edges per source node within the system.排序顺序:默认情况下,边链接按其目标节点的字典顺序排序。为了支持获取最新连接,Abstraction 在内存中检索目标边链接,按最后写入时间排序,并返回结果。为了确保最佳性能而不造成过多内存压力,我们旨在限制系统中每个源节点的边数量。

Next, let’s explore the caching strategies used by the Abstraction.接下来,让我们探讨 Abstraction 使用的缓存策略。

Caching Strategies in Graph Abstraction图抽象中的缓存策略

Although the Graph Abstraction already provides efficient reads and writes to durable storage, caching remains critical for the stability and performance of any graph datastore for two key reasons:尽管图抽象层已经提供了对持久化存储的高效读写,但缓存对于任何图数据存储的稳定性和性能仍然至关重要,原因有两个:

  • Write amplification: A single write on the fronting service can result in multiple writes to the backing durable storage due to the use of multiple indexes. Whenever possible, it’s best to avoid unnecessary writes — for example, by not writing an edge link that already exists.写放大:由于使用了多个索引,前端服务的一次写入可能导致对后端持久化存储的多次写入。应尽可能避免不必要的写入——例如,不写入已存在的边链接。
  • Read amplification: A single traversal request on the fronting service may translate into thousands of fetch operations on the backend, especially for highly interconnected graphs.读放大:前端服务的一次遍历请求可能转化为后端数千次获取操作,尤其是在高度互联的图中。

To address these challenges, the Graph Abstraction employs two distinct caching strategies.为应对这些挑战,图抽象层采用了两种不同的缓存策略。

Write-aside Caching of Edge Links边链接的写旁路缓存

An edge link contains no additional information beyond the link itself and its last-write timestamp. To reduce write amplification on durable storage, we cache edge links for short durations, helping to avoid writing a link that already exists. This mechanism is balanced with configurable TTL windows, cache invalidation on deletes, and lease acquisitions with exponential backoff. These strategies provide the necessary consistency guarantees while still allowing the last-write timestamp to be refreshed according to the predefined staleness.边链接除了链接本身及其最后写入时间戳外,不包含额外信息。为减少持久化存储上的写放大,我们将边链接缓存较短时间,有助于避免写入已存在的链接。该机制通过可配置的TTL窗口、删除时的缓存失效以及带指数退避的租约获取来平衡。这些策略在提供必要一致性保证的同时,允许根据预定义的陈旧度刷新最后写入时间戳。

Press enter or click to view image in full size

Read-aside Caching of Properties属性的读旁路缓存

To reduce read amplification on the durable store, the Graph Abstraction leverages KV’s integration with EVCache. Multiple KV namespaces can share the same caching clusters for cost efficiency. The Abstraction first fetches data from durable storage, while subsequent reads are served from the cache. Caching is applied at both the record and item levels, benefiting all graph objects.为减少持久化存储上的读放大,图抽象层利用了KV与EVCache的集成。多个KV命名空间可共享同一缓存集群以提高成本效率。抽象层首先从持久化存储获取数据,后续读取则从缓存提供。缓存应用于记录和条目两个级别,惠及所有图对象。

Graph Abstraction employs two invalidation strategies, selected based on write throughput and consistency requirements:图抽象层采用两种失效策略,根据写入吞吐量和一致性需求选择:

  • Invalidation on write: Both record and item caches are invalidated with every write, ensuring consistency across regions. This strategy is ideal for graphs that change infrequently and cannot tolerate data staleness, but comes with the tradeoff of pushing a higher throughput on the cache.写入时失效:每次写入时,记录和条目缓存均失效,确保跨区域一致性。该策略适用于变化不频繁且不能容忍数据陈旧度的图,但代价是增加缓存的吞吐量。
  • TTL-driven invalidation: Cache entries are invalidated only when their TTL expires. This approach works best for frequently modified objects that can tolerate some staleness.TTL驱动失效:缓存条目仅在TTL过期时失效。此方法最适合频繁修改且能容忍一定陈旧度的对象。

Work In Progress: Write-Through Caching进行中:写直达缓存

We are also developing a write-through caching strategy designed to store most of the data required by the Abstraction during traversals. This caching mechanism can organize indexes by different sort orders (e.g., sorting data by last-write timestamp), at the cost of increased memory consumption. Stay tuned for more details on this approach.我们还在开发一种写透缓存策略,旨在存储抽象层在遍历过程中所需的大部分数据。这种缓存机制可以按不同的排序顺序组织索引(例如,按最后写入时间戳对数据进行排序),代价是增加内存消耗。敬请期待关于此方法的更多细节。

Next, let’s examine the consistency guarantees in Graph Abstraction and how they are enforced for both reads and writes.接下来,让我们探讨图抽象中的一致性保证,以及它们如何对读写操作进行强制实施。

Consistency Enforcement一致性强制实施

Enforcing data consistency in Graph Abstraction poses several challenges. The connected nature of the data, low-latency API requirements, and the need to handle intermittent failures have led to design choices that enforce strict eventual consistency across multiple regions.在图抽象中强制实施数据一致性面临若干挑战。数据的关联性、低延迟API要求以及处理间歇性故障的需求,促使我们选择了跨多个区域强制实施严格最终一致性的设计。

Entropy Repair熵修复

Each write in the Abstraction persists data for both inward and outward indices in parallel to support high throughput. Further, each write happens on multiple KV namespaces. To prevent inconsistencies or lasting entropy from failures in any operation, the Abstraction uses a robust retry mechanism using Kafka:抽象层中的每次写入都会并行持久化入向和出向索引的数据,以支持高吞吐量。此外,每次写入都会在多个KV命名空间上进行。为了防止任何操作失败导致的不一致或持久性熵,抽象层使用基于Kafka的健壮重试机制:

Press enter or click to view image in full size

Node Deletions节点删除

Deleting nodes in a highly connected graph is more complex than simply removing a KV record as each node may have thousands of connected edges that must be handled to maintain graph integrity. Further, synchronously deleting all such connections would introduce unacceptable latency for the Abstraction callers.在高度关联的图中删除节点比简单地删除KV记录更复杂,因为每个节点可能有数千条关联边需要处理以维护图的完整性。此外,同步删除所有这些连接会给抽象层调用者带来不可接受的延迟。

The Abstraction employs an asynchronous deletion strategy to manage this issue. The consequence of this approach, however, is that the observed mutated state is only eventually consistent. Further, to ensure correctness of asynchronous deletes during concurrent updates, the Last-Write-Wins (LWW) conflict resolution mechanism is essential.抽象层采用异步删除策略来管理此问题。然而,这种方法的后果是观察到的变异状态仅最终一致。此外,为了确保并发更新期间异步删除的正确性,最后写入胜出(LWW)冲突解决机制至关重要。

Press enter or click to view image in full size

Global Replication全局复制

The consistency guarantees of Graph Abstraction are shaped by its multi-region availability. As illustrated in the diagram below, both the caching layer and durable storage replicate data asynchronously across regions, resulting in an eventually consistent system.图抽象的一致性保证由其多区域可用性决定。如下图所示,缓存层和持久存储层都跨区域异步复制数据,从而形成一个最终一致的系统。

Press enter or click to view image in full size

Now that we’ve covered storing the real-time graph index, let’s see how it enables graph traversals.现在我们已经介绍了实时图索引的存储,接下来看看它如何支持图遍历。

Graph Traversals图遍历

The Abstraction provides a custom gRPC traversal API, inspired by Gremlin, which enables exploration of the distributed graph by letting users chain traversals, apply filter criteria, sort results, limit results, and more.该抽象层提供了一种自定义的gRPC遍历API,灵感来源于Gremlin,允许用户通过链式遍历、应用过滤条件、排序结果、限制结果等方式探索分布式图。

Let’s explore a hypothetical scenario where the Abstraction is used to recommend shows to users on a shared device, by considering the duration of the most recent viewing session for each show across all profiles and accounts associated with that device:让我们探讨一个假设场景:抽象层用于在共享设备上向用户推荐节目,通过考虑该设备上所有配置文件和账户中每个节目最近观看会话的时长。

TraversalRequest.newBuilder()
.setNamespace("<graph-namespace>")
.setTraversalQuery(
TraversalQuery.newBuilder()
// Given id of the 'device' node type.
.setStartNode(node("device", "my-device-id"))
.setTraversal(
Traversal.newBuilder()
// fetch the first 5 connections
.setEdgeLimit(5)
.setDirectionTraversal(
DirectionTraversal.newBuilder()
// traverse in the IN direction
.setDirection(IN)
// minimize data exchange: only interested in certain properties
.addNodePropertiesSelections(propSelection("account", "created_at"))
.addNodePropertiesSelections(propSelection("profile", "last_active"))
.setDirectionFilter(
DirectionFilter.newBuilder()
// only interested in certain connected types
.setTypeMatchingStrategy(EXCLUDE_NON_TARGETED)
.addAllNodeFilters(typeFilters("account", "profile"))))
// chain traversals to the intermediate result
.addNextTraversals(
Traversal.newBuilder()
.setOrder(LATEST)
// limit to 200 connections for the 2nd hop
.setEdgeLimit(200)
.setDirectionTraversal(
DirectionTraversal.newBuilder()
// now traverse in the OUT direction
.setDirection(OUT)
.addEdgePropertiesSelections(propSelection("watched", "view_time"))
.addEdgePropertiesSelections(propSelection("has_plan", "active"))
.setDirectionFilter(
DirectionFilter.newBuilder()
.setTypeMatchingStrategy(EXCLUDE_NON_TARGETED)
.addAllNodeFilters(typeFilters("title", "plan")))))))
.build();

And let’s visualize the intended results set produced by the request above:让我们可视化上述请求产生的预期结果集:

Press enter or click to view image in full size

We’ll explore the design and implementation of traversal planning and execution, along with different traversal types, in the Part II of this blog series.我们将在本博客系列的第二部分中探讨遍历规划和执行的设计与实现,以及不同的遍历类型。

Now let’s look at the performance metrics of Graph Abstraction based on current production use cases.现在,让我们基于当前生产用例来看一下图抽象层的性能指标。

Real World Performance实际性能

Across all applications at Netflix, Graph Abstraction ensures high availability while processing up to 10 million operations per second across all writes, individual edge / node reads and traversals at peak hours:在Netflix的所有应用中,图抽象层在高峰时段每秒处理多达1000万次操作(包括所有写入、单个边/节点读取和遍历),同时确保高可用性:

Press enter or click to view image in full size

Edge and node persistence achieve single-digit millisecond latencies (p99 shown in red, p90 shown in orange, and p50 shown in green):边和节点的持久化实现了个位数毫秒级的延迟(p99以红色显示,p90以橙色显示,p50以绿色显示):

Press enter or click to view image in full size

Traversal performance depends on the number of hops, the edge fanout at each stage, and associated filters and sort orders. We parallelize work as much as possible to reduce latencies. Typically 1-hop traversals are executed with single-digit millisecond latency:遍历性能取决于跳数、每个阶段的边扇出以及相关的过滤器和排序顺序。我们尽可能并行化工作以减少延迟。通常,1跳遍历以个位数毫秒延迟执行:

Press enter or click to view image in full size
1-hop traversal latencies1跳遍历延迟

We also support a Count API that performs counting traversals at a very high rate with similar latencies, which we will cover in Part II of this series:我们还支持计数API,以非常高的速率执行计数遍历,延迟类似,我们将在本系列的第二部分中介绍:

Press enter or click to view image in full size

Currently, the RDG is powered by 2-hop traversals with a higher degree of fan-out. While these operations can reach upwards of 100 ms in latency, the 90th percentile (p90) latency remains under 50ms.目前,RDG由2跳遍历驱动,具有更高的扇出度。虽然这些操作的延迟可能达到100毫秒以上,但第90百分位(p90)延迟仍低于50毫秒。

Press enter or click to view image in full size
2-hop traversal latencies2跳遍历延迟

We track the average and max edge fanout at different depths to give us insights into the traversal performance for different graph datasets.我们跟踪不同深度的平均和最大边扇出,以了解不同图数据集的遍历性能。

Press enter or click to view image in full size
Median edge fan-out中位数边扇出
Press enter or click to view image in full size
Max edge fan-out最大边扇出

Asynchronous operations such as node deletions can be slightly latent, but typically perform with sub-second latency:异步操作(如节点删除)可能略有延迟,但通常以亚秒级延迟执行:

Press enter or click to view image in full size

At the moment, we are storing close to 650 TB of data globally across all our graph datasets.目前,我们在全球所有图数据集中存储了近650 TB的数据。

Press enter or click to view image in full size

Conclusion结论

As Netflix scales further into new verticals such as live content, games, and ads, Graph Abstraction will remain crucial for uncovering and leveraging rich connections — while continuing to support a high throughput and availability at low latencies.随着Netflix进一步扩展到直播内容、游戏和广告等新领域,图抽象对于发现和利用丰富的连接关系仍将至关重要,同时继续支持高吞吐量和低延迟的可用性。

Stay tuned for Part II of this blog series, where we’ll explore the implementation of graph traversals, counting and constraint mechanisms.敬请关注本系列博客的第二部分,我们将探讨图遍历、计数和约束机制的实现。

In Part III, we’ll take a closer look at the temporal index implementation and its integration with the Time Series Abstraction.在第三部分中,我们将深入了解时间索引实现及其与时间序列抽象的集成。

Acknowledgments致谢

Special thanks to our stunning colleagues who contributed to Graph Abstraction’s success: Kaidan Fullerton, Joey Lynch, Sudhesh Suresh, Vinay Chella, Sumanth Pasupuleti, Vidhya Arvind, Raj Ummadisetty, Jordan West, Chris Lohfink, Joe Lee, Jingxi Huang, Jessica Walton, Prudhviraj Karumanchi, Akashdeep Goel, Sriram Rangarajan, Chris Van Vlack, Christopher Gray, Luis Medina, Ajit Koti, Mohidul Abedin.特别感谢为图抽象成功做出贡献的优秀同事们:Kaidan Fullerton、Joey Lynch、Sudhesh Suresh、Vinay Chella、Sumanth Pasupuleti、Vidhya Arvind、Raj Ummadisetty、Jordan West、Chris Lohfink、Joe Lee、Jingxi Huang、Jessica Walton、Prudhviraj Karumanchi、Akashdeep Goel、Sriram Rangarajan、Chris Van Vlack、Christopher Gray、Luis Medina、Ajit Koti、Mohidul Abedin。

--

Netflix TechBlog
Netflix TechBlog

Published in Netflix TechBlog

Learn about Netflix’s world class engineering efforts, company culture, product developments and more.

Netflix Technology Blog
Netflix Technology Blog

Written by Netflix Technology Blog

Learn more about how Netflix designs, builds, and operates our systems and engineering organizations