前言
对于应用程序来说,使用多个数据存储是一种常见的模式,其中每个数据存储都用于满足特定的需求,如存储形式化数据(MySQL 等)、提供高级搜索功能(ElasticSearch 等)、缓存(Memcached 等)等等。通常,在使用多个数据存储时,其中一个用作主存储,其他用作次存储。现在的挑战是如何保持这些数据存储的同步。
我们已经观察到了一系列不同的模式,试图解决多数据存储的同步问题,比如双写、分布式事务等等。然而,这些方法在可行性、健壮性和可维护方面有局限性。除了数据同步之外,一些应用程序还需要通过调用外部服务来增强数据。
为了应对这些挑战,我们开发了 Delta。Delta 是一个最终一致的、事件驱动的数据同步和增强平台。
现有的解决方案
双写
为了保持两个数据存储的同步,可以执行双写操作,即在对一个数据存储执行写操作之后,对另一个数据存储执行写操作。第一个写操作可以重试,如果第一个写操作在用完重试次数之后失败,则可以中止第二个写操作。但是,如果第二个数据存储写入失败,这两个数据存储就会失去同步。一种常见的解决方案是构建一个修复例程,周期性地将第一个存储区中的数据重新应用到第二个存储,或者只有在检测到差异时才这样做。
问题:
实现修复例程通常是专用的,可能无法重用。另外,在应用修复例程之前,存储之间的数据是不同步的。如果涉及两个以上的数据存储,则解决方案会变得越来越复杂。最后,修复例程会在主数据源活动期间给其增加大量的压力。
变更日志表
当一组表发生变动(如插入、更新和删除)时,更改项会作为同一事务的一部分添加到日志表中。另一个线程或进程不断轮询日志表中的事件,并将它们写入一个或多个数据存储中,在所有数据存储确认后可选择从日志表中删除事件。
问题:
这需要作为一个库来实现,并且在理想情况下不需要对使用它的应用程序进行代码更改。在多语言环境中,需要对每种支持的语言重复实现这个库,并且很难确保跨语言时特性和行为的一致性。
模式更改的捕获还存在另一个问题,有些系统(如 MySQL)不支持事务性模式更改[1][2]。因此,执行更改(如模式更改)并以事务方式将其写入变更日志表的模式并不总是有效。
分布式事务
分布式事务可用于实现跨多个异构数据存储的事务,以便将写操作提交给所有相关存储或不提交。
问题:
事实证明,分布式事务跨异构数据存储是有问题的。本质上讲,它们只能依赖于参与系统的最小公分母。例如,如果应用程序进程在准备阶段失败,XA事务将阻塞执行;此外,XA 不提供死锁检测,也不支持乐观并发控制方案。而且,某些系统(如 ElasticSearch)不支持 XA 或其他任何异构事务模型。因此,对于应用程序[3]来说,要保证跨不同存储技术的写操作的原子性仍然是一个具有挑战性的问题。
Delta
开发 Delta 是为了解决现有数据同步解决方案的局限性,并允许动态地增强数据。我们的目标是从应用程序开发人员中抽象出这些复杂性,这样他们就可以专注于实现业务特性。下面,我们将描述“电影搜索”,这是 Netflix 内部使用 Delta 的一个实际用例。
在 Netflix,微服务架构被广泛采用,每个微服务通常只处理一种类型的数据。核心电影数据驻留在一个称为 Movie Service 的微服务中,而诸如电影交易、人才、供应商等相关数据则由多个其他的微服务(例如 Deal Service、Talent Service 和 Vendor Service)提供。Netflix 工作室的企业用户通常需要根据不同的标准搜索电影以便跟踪制作情况,因此,对他们来说,能够搜索与电影相关的所有数据至关重要。
在采用 Delta 之前,电影搜索团队在索引电影数据之前必须从多个其他的微服务获取数据。此外,团队必须构建一个系统,通过查询其他人的更改来定期更新他们的搜索索引,即使根本没有更改。这个系统很快就变得非常复杂且难以维护。
图 1 采用 Delta 之前的轮询系统
在上了 Delta 之后,系统被简化为一个事件驱动系统,如下图所示。CDC (Change-Data-Capture)事件由 Delta-Connector 发送到 Keystone Kafka 主题。使用 Delta 流处理框架构建的 Delta 应用程序会消费该主题中的 CDC 事件,然后调用其他微服务来增强每个事件,并最终将增强后的数据发送到 Elasticsearch 中的搜索索引。整个过程几乎是实时的,这意味着只要将更改提交到数据存储,搜索索引就会更新。
图 2 使用 Delta 实现的数据管道
在接下来的部分中,我们将描述连接到数据存储并将 CDC 事件发布到传输层的 Delta-Connector。传输层则将 CDC 事件路由到 Kafka 主题的实时数据传输基础设施。最后,我们将描述应用程序开发人员可以用来构建他们的数据处理和增强逻辑的 Delta 流处理框架。
CDC(变更数据捕获)
我们开发了一个名为 Delta-Connector 的 CDC 服务,它能够实时捕获数据存储中提交的更改并将其写入流。实时更改是从数据存储的事务日志和转储中捕获的。之所以采用转储,是因为事务日志通常不包含更改的完整历史记录。更改通常被序列化为 Delta 事件,因此,如果更改来自事务日志或转储,使用者就无需担心。
连接器提供多种先进的功能,如:
除 Kafka 之外,还能够写进自定义输出。
能够在任何时候触发针对所有表、特定表或特定主键的手动转储。
可以以块的形式获取转储,因此在出现故障时不需要从头开始重做一遍。
不需要获取表锁,这对于确保数据库上的写流量不会被我们的服务阻塞是至关重要的。
通过跨 AWS 可用性区域的备用实例实现高可用。
我们目前支持 MySQL 和 Postgres,包括部署在 AWS RDS 及其 Aurora 版本中的时候。此外,我们支持 Cassandra(多主机)。我们将在以后的博文中更详细地介绍 Delta-Connector。
Kafka&传输层
Delta 事件的传输层基于Keystone平台的消息服务构建。
从历史上看,Netflix 的消息发布是针对可用性而不是持久性进行优化的(参见以前的博客)。折中的结果是各种边缘场景中可能出现代理数据不一致。例如,不洁群首选举将导致消费者可能重复或丢失事件。
对于 Delta,我们需要更强的持久性保证,以确保 CDC 事件能够到达次存储。为了实现这一点,我们提供了一个特殊用途的 Kafka 集群作为一个一等公民。下面是一些代理配置。
在 Keystone Kafka 集群中,不洁群首选举通常有利于生产者可用性。当一个不同步的副本被选为群首时,可能会导致消息丢失。对于新的高耐久性 Kafka 集群,为了防止这样的信息丢失,不洁群首选举被禁用。
我们还将复制因子从 2 增加到 3,并将最小同步副本从 1 增加到 2。写入此集群的生产者需要所有存储的应答,以确保 3 个副本中有 2 个拥有由生产者写入的最新消息。
当代理实例终止时,一个新实例将替换终止的代理。然而,这个新的代理将需要更新不同步的副本,这可能需要几个小时。为了提高此场景的恢复时间,我们开始使用块存储卷(Amazon Elastic block Store)代替代理上的本地磁盘。当新实例替换已终止的代理时,它现在就会附加已终止实例拥有的 EBS 卷,并开始捕捉新消息。这个过程将捕获时间从几小时减少到几分钟,因为新实例不再需要从空白状态复制。通常,存储和代理生命周期的独立大大降低了代理替换的影响。
为了进一步最大化我们的交付保证,我们使用了消息跟踪系统来检测由于极端情况造成的任何消息丢失(如分区群首的时钟漂移)。
流处理框架
Delta 的处理层基于 Netflix SPaaS 平台构建,该平台提供 Apache Flink 与 Netflix 生态系统的集成。该平台提供了一个自助服务 UI,在我们的容器管理平台 Titus 上管理 Flink 作业部署和 Flink 集群编排。自助服务 UI 还管理作业配置,并允许用户进行动态配置更改,而不必重新编译 Flink 作业。
Delta 提供了一个基于 Flink 和 SPaaS 的流处理框架,该框架使用注解驱动的 DSL(领域特定语言)来进一步抽象技术细节。例如,要定义一个通过调用外部服务来增强事件的步骤,用户只需编写以下 DSL,框架会将其转换为一个由 Flink 执行的模型。
图 3 Delta 应用程序中用于增强事件的 DSL 示例
处理框架不仅缩短了学习曲线,还提供了常见的流处理功能,如重复数据删除、规范化、弹性和容错,以解决一般的操作问题。
Delta 流处理框架由两个关键模块组成:DSL&API 模块和运行时模块。DSL&API 模块提供基于注解的 DSL 和 UDF(用户定义函数)API,供用户编写自定义处理逻辑(如过滤器和转换)。运行时模块提供 DSL 解析器实现,用于构建 DAG 模型中处理步骤的内部表示。执行组件解释 DAG 模型,初始化实际的 Flink 操作符并最终运行 Flink 应用程序。
图 4 Delta 流处理框架架构
这种方法有几个好处:
用户可以专注于他们的业务逻辑,而不需要学习 Flink 或 SPaaS 框架的细节。
可以通过对用户透明的方式进行优化,并且可以在不对用户代码(UDF)进行任何更改的情况下修复 Bug。
操作 Delta 应用程序对于用户来说非常简单,因为框架提供了开箱即用的弹性和容错能力,并收集了多种粒度的可用于警报的指标。
生产使用情况
Delta 已经运行了一年多,在 Netflix Studio 的许多应用程序中都扮演了重要角色。它帮助团队实现搜索索引、数据仓库和事件驱动的工作流等用例。下面是 Delta 平台的高层架构图。
图 5 Delta 高层架构图
我们将在后续的博文中发布关于关键组件(如 Delta-Connector 和 Delta 流处理框架)的技术细节。敬请期待。如果你有任何问题,也可以随时联系作者。
本文最初发布于 Netflix 技术博客,由 InfoQ 中文站翻译并分享。
原文链接:
Delta: A Data Synchronization and Enrichment Platform
评论