Netflix 工程师最近发布了对其分布式计数器抽象的深入研究,这是一项可扩展的服务,旨在在全球范围内以低延迟跟踪用户交互、功能使用情况和业务绩效指标。该系统构建于Netflix 的 TimeSeries Abstraction之上,通过可配置的计数模式、弹性数据聚合和全球分布式架构来平衡性能、准确性和成本。
计算事物可能听起来是一个简单的问题。然而,Netflix 的工程师强调了隐藏的复杂性:
分布式计数是计算机科学中的一个具有挑战性的问题。 [...] 在 Netflix,我们的统计用例包括跟踪数百万用户交互、监控向用户显示特定功能或体验的频率,以及在 A/B 测试实验期间统计多个方面的数据等。
截至撰写本文时,该服务在全球不同的 API 端点和数据集上每秒处理近 75K 计数请求,同时为其所有端点提供个位数毫秒的延迟。
各种分布式计数器操作的延迟信息(来源)
一些计数用例需要“尽力计数”,优先考虑低延迟和最低基础设施成本而不是绝对准确性。其他人则需要“最终一致的计数”,以确保精确和持久的计数,尽管会略有延迟并增加运营成本。高可用性、容错性和对幂等重试的支持需要在准确性、性能和可扩展性之间取得平衡。
虽然尽力而为计数器采用了相对简单的基于EVCache的实现,但 Netflix 使用基于 TimeSeries 抽象的事件驱动架构实现了最终一致性计数器。
每个计数操作都被记录为 TimeSeries 抽象中的不可变事件以及幂等键,确保持久性并启用幂等重试。后台汇总进程使用基于时间的窗口不断聚合这些事件,将中间计数存储在持久存储中。这种方法可以避免数据丢失,并通过数据存储的多区域复制支持一致的全局聚合。
记录的计数器事件的汇总过程(来源)
幂等性在分布式系统中起着至关重要的作用。在失败、重试和重复请求很常见的网络环境中,幂等性可确保重复操作产生与单次执行相同的结果,从而允许客户端重试其请求。作者强调了在这种环境下为客户提供的第二个有用策略:
对冲是指如果原始请求未在预期时间内返回响应,则客户端向服务器发送相同的竞争请求。然后,客户端以最先完成的请求进行响应。这样做是为了使应用程序的尾部延迟保持相对较低。只有当突变是幂等的时,这才能安全地完成。
TimeSeries 抽象本身是一个可扩展的高吞吐量数据平台,可以以毫秒级延迟存储和查询时态事件数据。它将数据组织成时间序列记录,按时间对事件进行分区,并在定义的时间间隔内对它们进行存储。每个事件都是不可变的、带有时间戳且唯一标识的,从而实现精确的记录保存并支持高效的时间范围查询。目前,它在高峰时段每秒处理全球所有数据集的近 1500 万个事件。
Netflix 的 TimeSeries 抽象的吞吐量(来源)
在Cassandra等存储解决方案(用于实现持久性)和Elasticsearch(用于索引)的支持下,抽象可确保全局可用性和可调一致性。其架构支持动态扩展、可配置保留策略和自适应查询优化,使其成为分布式计数器抽象等数据密集型服务的基础。
Netflix 工程师现在正在试验精确的全球计数器。这种计数器类型通过将预聚合计数与最近事件的实时增量相结合来增强实时聚合。它不是等待后台汇总,而是通过扫描自上次聚合以来未处理的事件来动态计算最新计数。虽然这会增加读取复杂性和资源使用量,但并行查询和动态批处理可保持较低的延迟,从而实现关键指标的近实时准确性。