28

金融巨头 Capital One 的无服务器实践

 4 years ago
source link: https://www.infoq.cn/article/5ydIS3A81M4MdFC5GJTy
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

2qaM7vY.jpg!web

你是否想过,在月底结账时,你才发现自己的账户有错误交易?也许你遇到过这种事,并且印象深刻。数字化革命让你可以随时随地获取自己的信息。无疑,我们离未来世界不远了。在这个世界,相关信息可以在有需要时出现,你无需去寻找。

Capital One 正致力于使我们做的几乎所有事实时化。通过改进云计算和大数据工程工具,它不断为解决方案增加实时特性。我们的团队一直专注于为客户带来与其相关的、实时的个性化洞察。我们试图找出客户消费行为中非常特殊的交易,例如餐厅消费高得离谱、重复账单的增加、全新免费试用的开始和多次重复交易等等。

经过多年发展,Spark 框架逐渐发展成大规模实时流和批处理需求的首选技术。但是,伴随强大计算能力而来的是更高的操作和维护成本,我们开始体会到为满足实时流需求而运营 Spark 基础设施带来的痛苦。

所有,我们团队接受挑战,找到一个更简单、维护少且高度可伸缩的模式,并且围绕其设计一个无服务器流解决方案。

为何 Apache Spark 并非所有实时流用例中的 " 银弹 "?

据 D atabricks 的博客 ,Apache Spark 是处理大规模批处理和流数据的最快开源引擎之一。这点显而易见。既然 Spark 性能如此出色,为什么我们还要考虑使用其他的东西?

FZNVbyB.png!web

图片来自 Databricks blog

然而,让我们根据应用程序的需求评估下,比如:

  • 应用程序每秒加载记录是多少?如果它每秒低于几千,那 Spark 可能多余;
  • 为实现高弹性,应用程序所需的驱动程序和工作容器的最小数量是多少?如果在云上,请考虑将其分布到多个可用区和区域;
  • 安装像 Zookeeper 这样的资源管理器来维护 Spark 集群需要多少容器?;
  • 你是否考虑过云或数据中心的区域故障?如果是,那你可能已经体验过让 Spark 集群跨区域可用的架构复杂性;
  • 你的工作负载每天是否是固定的?如果是就太棒了,这对你的生意有好处。但是,大多数实时系统在每天、每周和每年都有周期性的工作负载,所以一定要考虑在非高峰时间系统的利用率;
  • Spark 作业在任何时候都可能失败。你考虑过作业的错误处理、监控和自动恢复吗?要实现这一点,需要很大的开发工作量;

不要忘记开发成本,这是所有成本中最大的一部分。考虑工程师在开发 Spark 基础设施时所需的所有特殊技能,比如像 Scala 或 Python 这样的编程语言、安装和管理 Spark 基础设施的脚本知识以及 Spark 缓存等。

尽管 Apache Spark 有着令人印象深刻的效果,但是如果你关心 Apache Spark 的运营开销,那么无服务器流解决方案可能是更好的选择。事实上,大多数实时流用例的加载速度都低于每秒 1000 个事务。

不必因为小的工作负载而去应对 Spark 基础设施的复杂性。相反,使用无服务器流解决方案来简化你的代码,可以极大降低成本和复杂性。

一个架构良好的流解决方案包含哪些?

在实现几个与流相关的用例后,我认为理想的流解决方案应满足以下需求:

伸缩

在现代应用程序架构中,自动伸缩被视为基本的设计考虑因素之一。在云计算时代,你可以根据需求获得无限的计算能力,因此不需要因为峰值负载进行扩展并支付额外费用。

虽然你能规划好主要的周期性工作负载,但是,在传统的基于服务器的基础设施中,你很难在一分钟内对其进行优化。理想情况下,应用程序应该能在请求出现较大峰值时自动修复以及自动伸缩。

限流

通常,流应用程序被设计成每秒接收成千上万个请求,并最终降到一个更易于管理的范围。当出现意料之外的峰值时,流应用程序可以横向扩展,但是下游的阻塞调用(API、DB 等)可能无法扩展。

因此,限流成为任何流应用程序的基本需求之一。记住——你系统的好坏取决于最薄弱的环节。

容错

应用程序总是与其他资源(如 API、数据库等)相连接。相关系统难免出现故障,但同时,我们也希望保护应用程序不受这些问题的影响。

在流应用程序中,容错是关键需求之一,因为你不希望在后端系统宕机时丢失数据。

重用

与重新创建解决方案相比,我们常常更关注重用。重用的程度取决于组件的模块化和大小,而微服务是重用的最佳示例。通过使流解决方案的构建块更小且可配置,我们可以加强跨多个应用程序的组件重用。

监控

想象一下,数百万条消息 / 事件流经你的应用程序,你能跟踪每一条消息并了解该消息究竟发生了什么。当你构建面向客户的关键应用程序时,这一点变得更加重要,并且需要查明特定的客户事件究竟发生了什么。

因此,对于同步或异步系统来说,监控都非常重要。

我们是如何构建无服务器流架构的?

那么,我们如何构建我们的解决方案?

我们的无服务器流架构是基于事件驱动的微服务架构建模的,其中每个微服务使用消息总线彼此连接。

zIFbUjf.png!web

本质上,事件驱动的架构提供了我们需要的流解决方案的所有功能。基于云服务商提供的托管服务实现事件驱动架构,就可以构建无服务器的流解决方案。

对于上述模式,如果你将托管服务(如 AWS Lambda)作为微服务,AWS Kinesis 作为消息总线,就可以使用无服务器技术栈实现事件驱动的架构。

我们将整个架构分为三层——源、接收(Sink )和处理。

  • :在这一层中,微服务只负责从源获取数据。可以将其视为事件进入流应用程序的入口。 例如:从 Kafka 集群读取事件。
  • 处理 :该层负责处理从源层获得的事件。你还可以将其视为一个能拥有具体应用程序逻辑的层。 例如:过滤事件或调用 API 来针对事件做出决策。你可以有一个或多个处理层来映射、缩减或增加你的消息。
  • 接收 :这是应用程序的最后一层,在这里对事件进行最后操作。 例如:将事件存储到数据存储中,或者通过 API 调用触发其他进程。

下面是从消息驱动架构到 AWS 服务的映射。

EVjURnZ.png!web

在上图中,你可能会觉得有很多重复动作,特别是从 Lambda 到从 Kinesis 写 / 读的动作。你可以发挥创造力,针对重复的功能构建某种类型的库。

在 Capital One,我们正是这样做的。我们构建了内部 SDK 来抽象重复任务。SDK 有以下特点:

  • 从消息总线读写 :从消息总线(Kinesis 或将来的其他服务)读写事件。
  • 异常处理和重试 :主要有两种重试,阻塞和非阻塞。当后端应用程序失败时,你可以阻塞错误重试,直到它恢复。当你只希望特定事件重试而对其他事件没有任何影响时,使用非阻塞重试。
  • 秘密管理 :当你不希望在无服务器函数中存储凭据时,将需要此功能。你可以选择企业秘密管理工具,并将它们集成为你的库的一部分。
  • 监控 :我们创建了自定义的消息信封,其中包含帮助我们跟踪每条消息的元数据。SDK 可以替开发人员承担这些工作,在每个微服务进入 / 退出时插入 / 删除信封。
  • 日志记录 :为实现跨所有微服务的统一体验,你可以在 SDK 中构建日志记录模式。
  • 消息去重 :我们知道,大多数分布式快速数据系统保证至少一次传递。当你想要过滤掉重复的消息时,可以考虑将其抽象为库的一部分。你能使用哈希或其他方法来实现具有亚毫秒延迟的消息去重。

它如何满足我们的流解决方案需求

正如我们前面所讨论的,任何无服务器流解决方案都需要解决伸缩、节流、重用、容错和监控等问题。这是如何实现的呢?

伸缩

这种架构模式与天生可伸缩的云和服务相结合,让这一切成为可能。

  • 该模式使用 Lambdas 实现微服务,并通过 Kinesis 进行连接。我们只需要扩展具有高 TPS 的 Lambdas,随着消息被过滤掉,相应地调整规模配置。
  • 按照设计,无服务器函数是可自动伸缩的。例如:如果你使用 Lambdas 和 Kinesis,你可以扩展 Kinesis,如果你的消息吞吐量从 2MB/ 秒增加到 4MB/ 秒,这也将扩展与 Kinesis 相关的 Lambda 函数。

yMvEfqZ.png!web

限流

限流的基本功能是,如果你的输入请求速率远远高于下游所能支持的速率,则需要保存你的请求。在这里,消息总线持久化特性能帮助我们,因为你只能选择一次可以处理的消息数量,并保存其他消息。

例如:如果你使用 Kinesis 作为消息总线,则能指定你在函数中处理的批次大小。

重用

如果我们可以构建 source 微服务和 sink 微服务,让它们不具有任何业务功能,并且是基于配置的,那么就可以多个团队都使用它们来消费事件。

例如:如果你能构建源函数来消费来自 Kafka 的事件,这些事件可以对主题名称、代理地址等进行配置,那么任何团队都可以根据需要使用该函数并将其部署到他们的栈中,而无需更改任何代码。

以上可以帮助我们实现代码级的重用。另一种重用是流本身的重用。如果你为自己架构选择的消息总线是基于发布 / 订阅的总线,那么你能有多个订阅者来访问相同事件。例如:你可以将事件 fan out 到两个微服务,而无需单独编写额外代码。

容错

同样,消息总线在这里也可以对我们提供帮助。考虑一下,如果你的后端服务出现错误,你可以将所有 / 失败的消息保存到消息总线中,然后重试,直到后端调用开始成功。

监控

作为 SDK 的一部分,记录元数据有效负载能帮助我们实现跨不同功能的日志一致性。你还可以构建一个可重用的函数,该函数能将你的日志转发到首选的监控解决方案。

uQvuMfv.png!web

这听起来就像说无服务器流解决方案是银弹,我不需要 Spark

并非如此。Apache Spark 是一个分布式计算平台,在大规模分布式数据处理负载上表现出色。当涉及高容量计算和批处理时,数据和计算功能可以采用分布式,并且能并行执行,Spark 仍然是首选工具。典型例子包括机器学习用例的重量级计算需求,涉及几百个文件的 Map/Reduce 范式,或者处理 PB 级数据的长时间运行的进程等等。Spark 也能作为实时流领域的首选工具,但前提是流量非常大,每秒执行数十万个事务。

在 Capital One,我们使用多种多样的大数据工程工具。在我的团队中,我使用了无服务器流来处理大容量的用例,比如根据每秒数千个事件的客户交易生成有意义的警报,以及处理每秒数十个事件的小容量用例,比如补卡。我还使用 Spark 来处理大型交易文件,使用机器学习模型生成客户的消费档案。这完全取决于具体的需要。

英文原文:

Scaling to Billions of Requests-The Serverless Way at Capital One


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK