写点什么

一个典型的架构演变案例:金融时报数据平台

2021 年 1 月 04 日

一个典型的架构演变案例:金融时报数据平台

本文最初发布于金融时报产品 &技术博客,经原作者授权由 InfoQ 中文站翻译并分享。


英国金融时报是世界上最大的商业新闻机构之一,已有 130 多年历史,以其高质量的新闻报道而闻名。


要想长时间保持领先地位,就必须能够适应世界的变化。过去 10 年,为了利用技术提供的机遇,金融时报经历了一次数字化转型。


本文将深入介绍这一转型的幕后故事:金融时报数据平台的创建和演化。该数据平台提供读者与 FT 互动的信息,让我们能够决定如何继续为读者提供他们想要和需要的东西。


第一代:2008–2014 早期



起初,数据平台专注于根据读者已经阅读的内容做推荐。


当时,我们的大多数读者仍在阅读纸质版《金融时报》,因此,一个存储和 24 小时的延迟就足够了。该架构干净、简单,金融时报的员工能够在上面执行查询,分析用户兴趣。


但随后发生了一些事情。


  1. 互联网革命。互联网蓬勃发展,访问ft.com而非阅读纸质报纸的读者数量每天都在增加。

  2. 移动创新。移动设备开始成为人们日常生活的一部分。智能手机从一种奢侈品变成了一种预期,金融时报就针对每种最流行的操作系统发布了移动应用程序。这成了另一个用户流,让他们不管是在上班的路上,还是在家里休息,亦或是在户外享受大自然时,都可以从阅读文章中获益,而不必借助笔记本电脑。

第二代:2014–2016 提取、转换、加载(ETL)框架的到来



我们的第二代平台面临两个新的挑战:首先,需要使我们的涉众能够大规模地分析数据,提出新的问题;其次是数据量的增加。


为了实现这些目标,我们在 2014 年构建了自己的 ETL 框架。这使得我们的团队能够以自动化和可扩展的方式创建新的作业和模型,并包含如下特性:


  1. 调度。每天自动运行多次 SQL 查询,与其他团队同步输出结果,最后但同样重要的是,更多地关注业务用例而不是实现细节。

  2. Python 接口。除了 SQL 查询之外,还提供了运行 Python 代码的能力,允许涉众运行更复杂的数据模型。

  3. 重配置轻实现。选择引入 ETL 框架的其中一个原因是能够生成 XML 文件格式的作业,这在当时催生了更多的业务功能。


ETL 框架的发布产生了巨大的积极影响,但它本身并不能解决因为数据量和用户数增加而带来的所有问题。


实际上,从性能的角度来看,添加这个新组件实际上会带来更多的问题,因为数据平台的消费者数量增加了,现在包括商业智能(BI)团队、数据科学团队和其他团队。SQL Server 实例开始成为数据平台的瓶颈,也成为所有涉众的瓶颈。现在是做出改变的时候了,我们设法为这个特定的问题找到了最好的解决办法。


考虑到金融时报已经在使用 Amazon Web Services(AWS)提供的一些服务,我们开始评估 Amazon Redshift,将其作为一种快速、简单、划算的数据仓库,用于存储越来越多的数据。Amazon Redshift 是为云端在线分析处理(OLAP)而设计的,这正是我们一直在找的东西。使用这种方法,我们能够大幅优化查询性能,而不需要团队付出任何额外的努力来支持新的存储服务。

第三代:2016–2018 金融时报大数据时代来临


将 Amazon Redshift 作为数据仓库解决方案,将 ETL 框架作为部署提取、转换、加载作业的工具,所有 FT 团队都看到了拥有一个数据平台的好处。然而,当我们在一家引领市场的大公司工作时,比如在金融时报从事商业新闻发行时,我们不能满足于现有的成就。这就是为什么我们开始思考如何进一步改进这个架构。


我们的下一个目标是减少数据延迟。我们每天摄入一次数据,因此延迟时间长达 24 小时。减少延迟意味着 FT 可以更快地对数据趋势做出反应。



为了减少延迟,我们在 2015 年开始研究一种名为下一代数据分析(NGDA)的新方法,并在 2016 年初被金融时报的所有团队采用。


首先,我们开发了自己的跟踪库,负责将读者的每一次互动发送到数据平台。现有的架构需要一个 CSV 文件列表作为输入,这些文件由 ETL 框架运行的作业每天传输一次,因此,逐个发送事件意味着我们需要更改现有的架构以支持新的事件驱动方法。


然后,我们创建了一个 API 服务,负责接收读者的交互。但是,我们仍然需要一种方法,以尽可能低的延迟将这些数据传输到数据仓库,并将这些数据公开给多个下游消费系统。在我们将所有服务迁移到云(更具体地说是迁移到 AWS)上时,我们了解了 Amazon 提供的能够满足我们事件处理需求的托管服务。


在分析了各种备选方案之后,我们重新设计了系统,将ft.com的所有原始事件发送到简单通知服务(SNS)。这样一来,组织中的许多团队都可以订阅 SNS 主题,并根据实时数据解锁新的业务用例。


尽管如此,仅仅是在 SNS 中有这些原始数据还不够——我们还需要将数据放入数据仓库以支持所有现有的工作流。我们决定使用一个简单队列服务(SQS)队列,因为它让我们可以在所有事件到达系统时立即将它们持久化。


但是在将数据移动到数据仓库之前,我们还有一个来自业务的需求——使用由内部服务、外部服务或简单内存转换所提供的额外数据来丰富原始事件。为了在延迟最小的情况下满足这些需求,我们创建了一个NodeJS服务,负责在一个循环中异步处理所有事件,使得丰富步骤可以大规模地进行。事件经过充分的丰富之后,数据就会立即被发送到 AWS 当时提供的唯一托管事件存储 Kinesis 中。使用这种架构,我们能够在延迟数毫秒的情况下将丰富后的事件持久化,对我们的涉众来说,这是一个让他们惊喜的消息。


一旦数据进入 Kinesis Stream,我们就使用另一个 AWS 托管服务 Kinesis Firehose 消费经过丰富的事件流,并根据两个主要条件中的一个把它们以 CSV 文件的形式输出到一个 S3 bucket——一个预定义的已经过去的时间(很少发生)或文件大小达到 100MB。这种新的事件驱动方法根据一天的时间段在几分钟内生成包含丰富后事件的 CSV 文件,因此,我们的数据湖延迟被减少到 1-5 分钟。


但是,业务团队还有一个更重要的需求。他们要求数据仓库中的数据是干净的。使用 Kinesis Firehose 方法,我们不能保证只有一个事件实例,因为:


  1. 我们会从客户端应用程序接收到重复的事件。

  2. 当 Firehose 作业失败重试时,Kinesis Firehose 本身会复制数据。


为了删除所有重复的事件,我们另外创建了一个 Amazon Redshift 集群,负责摄入每个新进来的 CSV 文件并进行去重。这涉及到一个权衡:实现一个保证惟一性的流程,将数据进入数据仓库的延迟提高到大约 4 个小时,但可以使我们的业务团队更轻松地生成洞察。

第四代:2019 重建平台让团队专注于增加业务价值



第三代平台运行起来很复杂。我们的团队把大部分时间都花在了支持大量的独立服务上,工程成本增加了,从事有趣而又有影响力的工作的时间少了很多。


我们希望利用新技术来降低这种复杂性,同时也为涉众提供更加令人兴奋的功能:我们希望将数据平台转换为 PaaS(平台即服务)。


根据最初的标准,平台应该提供:


  • 自助服务——使涉众能够独立开发和发布新特性。

  • 支持多个内部消费者——不同的团队拥有不同的访问级别。

  • 安全隔离——团队只能访问他们自己的数据和作业。

  • 代码重用——避免通用功能重复。


构建多租户、自助服务平台非常具有挑战性,因为它需要每一项服务都同时提供这些支持。尽管如此,努力实现这一方法对未来的发展极为有利,主要的好处如下:


  • 涉众团队无需等待与平台团队协调就可以交付价值——这降低了成本,提高了速度,并让他们对自己负责;

  • 平台团队可以专注于为平台构建新的功能——而不是把时间花在清除涉众团队的障碍上。


我们选择用来提供这种解耦的方式是重配置而轻实现,涉众团队能够基于其内部团队的结构、角色和权限,使用一个管理 Web 界面设置自己的管理规则。

Kubernetes


一个软件系统就像一座房子。你需要从地基开始建,而不是从屋顶开始。在工程中,地基就是基础设施。没有稳定的基础设施,就不可能有一个生产就绪的稳定的系统。这就是为什么我们从基础设施开始,从短期和长期两个方面讨论未来的最佳方法。


我们现有的数据平台已经部署到 AWS ECS 中。虽然 AWS ECS 是一个非常棒的容器编排器,但我们还是决定切换到Kubernetes,因为 EKS 提供了许多我们为提供多租户支持所需要的功能,比如租户之间的安全隔离、每个租户的硬件限制等等。除此之外,还有许多开箱即用的 Kubernetes Operators,比如spark-k8-operatorprometheus-operator等等。AWS 提供托管的 Kubernetes 集群(EKS)已经有一段时间了,不管是从短期来看,还是从长期来看,它都是数据平台基础设施的不二选择。为了拥有一个提供自助服务的多租户数据平台,我们不得不对每个服务和 Kubernetes 集群本身提几个要求:


  • 系统命名空间——将所有的系统组件都分隔到一个单独的 Kubernetes 命名空间中,由它负责管理所有的服务。

  • 团队命名空间——将团队所有资源分组到一个 Kubernetes 命名空间中,以便为每个团队自动应用基于团队的配置和约束。

  • 对每个命名空间进行安全隔离——限制 Kubernetes 集群中的跨命名空间访问,以防止不同团队的资源之间意外地交互。

  • 为命名空间设置资源配额——当其中一个团队达到硬件限制时,不会影响所有团队,并可以通过计算每个团队的花费和交付的业务价值的比值来衡量效率。

批处理


我们的 ETL 框架非常稳定,并且已经运行了多年,但为了充分利用我们采用的云原生技术,我们需要一个新的框架来支持:


  • 云部署

  • 水平扩展。随着工作流数量和数据量的增加,我们希望扩展尽可能简单。

  • 多租户。因为整个平台需要这项支持。

  • 部署到 Kubernetes。同样,为了与整个平台保持一致。


自从我们构建了 ETL 框架之后,人们对 ETL 的期望一直在变化。我们希望能够支持:


  • 语言无关的作业。为了最大限度地利用使用数据平台的所有团队的不同技能集。

  • 工作流的概念。需要在工作流中定义相互依赖的一系列作业,这是另一个为了可以在日常工作中做出数据驱动决策的关键业务需求。

  • 代码可重用。工作流中部分步骤的功能存在重复,它们是不错的代码重用候选对象。

  • 自动化 ETL 作业分布式回填。因为这个过程在我们的新用例中经常发生,所以自动化将提高业务速度。

  • 监控。我们需要良好的监控,以防止基于低质量、高延迟甚至是缺失数据做出数据驱动的决策。

  • 可扩展性。基于涉众提供的反馈和需求扩展批处理服务的能力,使得该服务在可预见的未来足够灵活。


另一个大的变化是功能齐全的 ETL 框架现在已经有了,不再需要从头开始构建。


考虑到所有这些需求,我们评估了市场上存在的不同选项,如 Luigi、Oozie、Azkaban、AWS Steps、Cadence 和 Apache Airflow。


最适合我们需求的是Apache Airflow


尽管它很棒,但仍有一些局限——比如只有一个调度程序和缺少多租户原生支持。虽然根据基准测试、估计负载以及该特性将在 Apache Airflow 2.0 中发布的预期,第一个问题我们不是特别关心,但第二个问题会影响我们的整个架构,所以我们决定在 Apache Airflow 之上构建自己的多租户支持。


我们考虑过使用一个 Apache Airflow 托管服务(有多个供应商),但最终,考虑到多租户、语言无关的作业和监控等需求,我们还是决定继续使用自托管的解决方案。所有这些都无法通过托管解决方案实现,所以就有了扩展需求,这对我们来说很重要。


把 Apache Airflow 集成到平台中之后,我们就开始在其上发布新的工作流,以保证其功能。当我们认识到它符合所有标准时,下一步就很明显了,目前我们正在将所有现有的 ETL 作业迁移到 Apache Airflow 中。除此之外,我们已经将它作为一个自助服务产品发布给公司的所有涉众,我们的消费者现在已经包括 BI 团队、数据科学团队,等等。

第五代:2020 实时数据的时间到了



第四代平台有很大的进步。但是,仍有一些改进目标。

实时数据


对于很大一部分数据,我们的延迟仍然是 4 个小时左右。


在大多数情况下,4 个小时的延迟是去重过程所导致的——这个过程对我们的涉众及其需求来说非常重要。例如,金融时报不能基于低质量的数据做出任何业务发展决策。这就是为什么我们必须确保数据仓库能为这些用例提供干净的数据。


然而,随着产品、业务和技术的发展,新的用例出现了。 它们可以使用实时数据来产生影响,即使有小比例的低质量数据也没关系。一个很好的例子是,在ft.com和移动应用程序中,根据读者的兴趣对推送给用户的内容进行排序。对于这个用例来说,存在事件重复也影响不大,因为用户体验总会比不考虑用户兴趣就向所有用户推送相同的内容要好得多。


我们已经有了一个稳定的流处理架构,但它相当复杂。我们开始考虑对其进行优化,从 SNS、SQS 和 Kinesis 迁移到使用Apache Kafka作为事件存储的新架构。事件存储托管服务是我们的首选项,我们决定试一下 Amazon MSK,因为很长一段时间以来,它似乎就已经很稳定了。


在 Apache Kafka 主题中摄入数据是向业务提供实时数据的一个很好的开端。然而,涉众仍然无法访问 Apache Kafka 集群中的数据。因此,我们的下一个目标是创建一个流处理平台,让他们部署基于实时数据的模型。我们需要一些与架构其他部分相匹配的东西——支持多租户、自助服务、多语言以及可部署到 Kubernetes。


考虑到这些需求,Apache Spark似乎非常适合我们,它是最常用的分析引擎,也是世界上最大的开源社区之一。


为了将 Apache Spark 流作业部署到 Kubernetes,我们决定使用spark-on-k8s-operator


此外,我们的 Data UI 有一个界面,涉众可以通过它将 Apache Spark 流处理作业部署到生产环境,只需要填写一个简单的表单,其中包含了与作业相关的信息,如 Docker 镜像和标签、CPU 和内存限制、作业中使用的数据源凭证,等等。

数据契约


另一个我们需要进行优化的方面是,将数据验证移到管道中尽可能早的步骤里。我们有对进入数据平台的数据进行验证的服务,但是这些验证是在管道的不同步骤执行的。这会导致问题,因为管道有时会因为传入的数据不正确而中断。这就是为什么我们想通过提供以下特性来做出改进:


  • 管道中事件流的数据契约;

  • 将验证步骤移到尽可能早的步骤中;

  • 压缩以减少事件大小。


考虑到所有这些需求,我们找到了一种使用Apache Avro来实现这些需求的好方法。它让我们可以为 Apache Kafka 中的每个主题定义一个数据契约,从而确保集群中的数据质量。


这种方法还解决了另外一个问题——验证步骤可以移到管道中的第一步。借助 Apache Avro 模式,在使用 Apache Spark 流作业时就可以防止我们将不正确的事件转移到其他用作 Dead Letter Queues 的 Kafka 主题中,从而防止管道中进入有问题的数据。


Apache Avro 的另一个重要特性是序列化和反序列化,这使得它能够对保存在 Apache Kafka 事件存储中的数据进行压缩。

数据湖


从 CSV 迁移到数据湖存储中的 parquet 文件,是可以满足我们大多数需求的最佳初始选项。但是,我们仍然缺少一些可以使我们的工作更轻松的特性,包括 ACID 事务、模式约束以及在 parquet 文件中更新事件。


在分析了市场上现有的所有替代方案(包括HudiIcebergDelta Lake)之后,我们决定开始使用支持 Apache Spark 3.x 的 Delta Lake。它满足了我们所有的主要需求,非常适合我们的架构。


  1. 效率。我们将计算过程从存储中解耦,从而使我们的架构可以更有效地扩展。

  2. 低延迟、高质量的数据。使用 Delta Lake 提供的 upsert 和模式约束功能,我们可以持续地向金融时报的所有涉众交付低延迟、高质量的数据。

  3. 多接入点。将所有传入数据持久化到 Delta Lake 中,允许涉众通过多个系统(包括 Apache Spark 和Presto)查询低延迟数据。

  4. 时间旅行。除了允许在不同的用例(如生成报告或训练机器学习模型)中针对特定的日期间隔进行分析之外,Delta Lake 还允许从过去的一个特定时间开始对数据进行再处理,从而自动化反向数据填充。

虚拟化层


在金融时报,我们公司的团队使用了不同类型的存储,包括 Amazon Redshift、谷歌 BigQuery、Amazon S3、Apache Kafka、VoltDB 等。然而,涉众常常需要跨多个数据存储分析数据,以便做出数据驱动的决策。为了满足这个需求,他们使用 Apache Airflow 在不同的数据存储之间移动数据。


然而,这种方法远不是最佳的。使用批处理方法会给增加额外的数据延迟,在某些情况下,使用低延迟数据做出决策对于业务用例至关重要。此外,部署批处理作业需要更多的技术背景,这可能会限制一些涉众。了解了这些具体信息,我们就更清楚,涉众为了向读者提供更多的价值需要什么了,它需要支持:


  • 对任何存储的实时查询;

  • ANSI SQL ——他们通常都熟悉这个语法;

  • 连接不同数据存储的数据。


我们希望能够部署到 Kubernetes 上,以适应我们的平台架构。


在分析了市场上的不同选项之后,我们决定从Presto入手,因为它让企业可以大规模地分析 PB 级的数据,而且能够连接来自许多数据源的数据,包括金融时报使用的所有数据源。

未来规划


在金融时报,我们从不满足于自己已经取得的成果,这也是该公司 130 多年来一直处于行业领先地位的原因之一。这也是为什么我们已经规划好如何进一步演进这个架构。


  • 摄入平台。我们通过三个组件来摄入数据——由 Apache Airflow 控制的批处理任务、消费 Apache Kafka 流数据的 Apache Spark 流处理作业,以及等待数据进入数据平台的 REST 服务。我们的目标是用 Change Data Capture(CDC)取代现有的高延迟摄入服务,这将使新数据在到达任何数据源时都能立即摄入,这样一来,业务将能够为我们的读者提供更好的体验。


  • 为每个人提供实时数据。我们考虑的一个主要特性是,让金融时报的所有人都能访问这些数据,而不需要具备特殊的技术技能。为了做到这一点,我们计划增强数据 UI 和流处理平台,允许通过拖放来构建流处理作业。这将是一个巨大的进步,因为它将使没有技术背景的员工能够消费、转换、生产和分析数据。


查看英文原文:

Financial Times Data Platform: From zero to hero


2021 年 1 月 04 日 16:121953

评论 2 条评论

发布
用户头像
mark
2021 年 01 月 11 日 11:15
回复
用户头像
嗯... kafka+clickhouse
2021 年 01 月 05 日 16:07
回复
没有更多了
发现更多内容

奈学教育:Hadoop源码编译全流程分享

奈学教育

浅谈敏捷开发中的设计

czjczk

敏捷开发

MyBatis之启动分析(一)

ytao

mybatis Java 面试

重学 Java 设计模式:实战适配器模式

小傅哥

设计模式 小傅哥 重构 代码质量 代码坏味道

ARTS 01 - 技术人的理想主义

jerry.mei

算法 Vue 练习 ARTS 打卡计划 ARTS活动

Docker 容器优雅终止方案

米开朗基杨

Docker

入门到放弃:理清前端技术概念

大伟

Java ecmascript 前端 Node

这场大数据+AI Meetup,一次性安排了大数据当下热门话题

Apache Flink

大数据 flink 流计算 实时计算 大数据处理

Mobaxterm (安装 、汉化、使用)入门教程

Geek_Offset

程序员都惧怕的故障域

松花皮蛋me

Java 问题处理

游戏夜读 | 如何管理公司?

game1night

Java 走过的创新25年

田晓旭

Java25周年

Shell 文本处理一则

wong

Shell sed grep

吉德热泵烘干机解放阳台,引领生活品质新风尚

infoq小陈

【译】5 个你需要知道的 JavaScript 小技巧

零和幺

Java 前端 技巧

深入理解JVM内存管理 - 堆和栈

NORTH

堆栈 深入理解JVM VM参数

LeetCode | 2. Reverse Integer 整数反转

Puran

Python C# 算法 LeetCode arts

普通二本,毕业三年,北漂之后,我是怎么成为程序猿的。

why技术

个人成长 程序人生 随笔杂谈 北漂

http 四种鉴权方式简介,未来可能还会出现第 5 种鉴权方式:全息生物验证

李艺

HTTP

【Sentry搭建之 docker-compose】

卓丁

DevOps Docker-compose CI/CD sentry

【大厂面试02期】Redis过期key是怎么样清理的?

NotFound9

Java 数据库 redis 架构 后端

手撕编译原理:汇编语言不会编

贾献华

Flink 1.10 SQL、HiveCatalog 与事件时间整合示例

Apache Flink

大数据 flink 流计算 实时计算 大数据处理

Flink Weekly | 每周社区动态更新-20200520

Apache Flink

大数据 flink 流计算 实时计算 大数据处理

千万别学编译原理

池建强

编译原理

如何挑选一份工作

池建强

求职 找工作

原创 | TDD工具集:JUnit、AssertJ和Mockito (十六)编写测试-有条件执行测试

编程道与术

Java 编程 TDD 单元测试 JUnit

微信小程序开发 | 如何在小程序中使用自定义 icon 图标

彭宏豪95

微信小程序 学习 编程 前端 IT

centos7分区命令parted的用法(大于2T)

唯爱

缓存与存储的一致性策略:从 CPU 到分布式系统

伴鱼技术团队

缓存 系统设计 cpu 系统架构 架构模式

产品的本质,知道却看不到

Neco.W

产品 产品经理 需求 产品开发

NLP领域的2020年大事记及2021展望

NLP领域的2020年大事记及2021展望

一个典型的架构演变案例:金融时报数据平台-InfoQ