Kinesis是由AWS提供的一项流数据管理服务,可轻松收集、处理和分析实时流数据。本文详细介绍了迪士尼API服务团队如何实现Kinesis数据流的自动缩放功能,保证流量高峰时的数据传输效率,并有效降低成本。本文来自迪士尼技术博客。
文 / Nick Burkard
译 / 咪宝
原文
https://medium.com/disney-streaming/delivering-data-in-real-time-via-auto-scaling-kinesis-streams-72a0236b2cd9
摘要
Kinesis是Amazon Web Services(AWS)提供的一项托管式流数据服务,在迪士尼流媒体服务中被广泛应用于实时和批量分析,并支持个性化视图、流并发和应用程序域事件分析等功能。在本篇文章中,将详细介绍迪士尼流媒体服务的API服务团队是如何实现Kinesis数据流的自动缩放功能的,这项功能使我们能够在流量高峰时段稳定地传输数据,同时保持成本效益。
问题
团队的工作
在迪士尼流媒体服务中,我们的API服务团队(包括我自己)负责那些向客户端公开公共API的应用程序,这意味着我们将大量参与客户端通信协议、支持流量需求的扩展、通过回退和降级提供可靠性以及安全性。
与大多数使用AWS部署的应用程序一样,我们的应用程序将事件记录到CloudWatch日志中。由于CloudWatch也是AWS提供的一项管理服务,因此我们可以很容易地集成它来存储和查询应用程序事件。我们还将应用程序事件发布到一个更大的数据湖平台中,这个平台支持对应用程序事件进行更丰富的分析和可视化,这也就是Kinesis 数据流的来源。
动机
选择Kinesis流作为我们的数据湖平台的入口点,需要确保数据不会丢失或长时间落后于实时交付。
一个简单的解决方案是过度供应流。然而,这并不划算,因为它相当于一天的大部分时间里都在浪费钱。
我们还研究了AWS Labs提供的一个应用程序Kinesis Scaling Utility,它可以通过CloudWatch来监控指标,并根据配置扩展Kinesis流。但是,它不是满足我们需求的最佳解决方案:
原因如下:
- 扩大规模的速度不够快。
- 应用程序需要不断运行,这会产生额外的成本。
上述两点是应用程序监控指标方法的结果,每隔设定的时间间隔来查询CloudWatch。我的团队需要尽快进行扩展并且节约成本,因此我们开始创建自己的解决方案。
有关Kinesis的基础知识
为了更好地理解为我们的解决方案做出的选择,我将介绍Kinesis流如何工作的一些基础知识。有关进一步介绍的文档,请参阅AWS提供的关键概念页面。(https://docs.aws.amazon.com/zh_cn/streams/latest/dev/key-concepts.html#terminology)
分片
Kinesis流在创建时分配了一定数量的分片。流中的每个分片都有一个散列键范围,它是一系列有效的整数值。在创建时,这些分片被认为是开放的,这意味着它们可以接收数据并产生成本。
对于添加到流中的每条记录,必须定义分区键。流散列此分区键,结果为整数。流确定生成的整数落入哪个散列键范围,并将记录发送到正确的已打开分片。
在向流中添加记录时,可以选择定义显式哈希键,这将强制将记录发送到特定的开放分片。
缩放
缩放Kinesis流的过程称为重新分片,它可以通过调用UpdateShardCount来异步启动,必须提供目标分片用以计数(要缩放的分片数)。
向下缩放流合并成对的分片以实现所需的总数。向上缩放流将多个分片分成两半以获得所需的总分。
这意味着可以将最小的流缩小到其当前打开的分片计数的一半。相反,这也意味着可以将最高的流扩展为其当前打开的碎片计数的两倍。
例如,Kinesis流有12个开放分片。在此流上调用UpdateShardCount时,目标分片计数必须在[6,24]的范围内,超出此范围的值将导致错误。
数据的可用性
Kinesis流具有设定的数据保留期,默认为24小时。
重新进行分片后,分片将被关闭,这意味着它们无法再接收数据。它们不会产生成本并将保留到数据保留期后。
要求
为了实现将CloudWatch日志数据提供给自动扩展Kinesis流的目标,需要创建几个不同的组件。我们将这些组件组织成两个单独的堆栈,以确保将来可重用。
自动缩放堆栈
在大量使用期间缩放Kinesis流及其相关资源,在非高峰时段缩小。
Kinesis流
已处理数据的主要目标。此数据可以驱动实时处理或存储以进行批量分析。
此流可以与其关联的扩展组件同时创建,也可以在AWS环境中存在。
扩展
Lambda可以扩展Kinesis流,根据Kinesis指标和可选的外部Lambda的计算吞吐量触发它的警报。处理触发扩展Lambda的警报跟踪Kinesis流报告的度量。
为了跟踪何时进行扩展,Lambda将在成功调用时向CloudWatch报告两个自定义指标(OpenShards和ConcurrencyLimit)。这些自定义指标将允许我们监控扩展行为。
缩小
Lambda可以缩小Kinesis流、缩放警报以及可选的外部Lambda到原始设置。
在非高峰时段(处理失败的日志之后)每天一次,CloudWatch规则将以10分钟的间隔触发Scale Down Lambda。这样做的目的是为了抵消Kinesis缩小的限制(最低有效目标分片计数是当前打开分片计数的一半)。
如果当前正在大量使用流,如果当前正在按比例缩小或者已经缩小到默认的分片数量,则此Lambda将跳过缩小过程。
与扩展Lambda一样,只要成功调用,Lambda也会向CloudWatch报告两个自定义指标(OpenShards和ConcurrencyLimit)。
日志处理堆栈
从CloudWatch 日志处理事件,将结果发送到Kinesis流。
记录处理器
Lambda将处理来自所选日志组的事件,将结果发送到Kinesis流。
如果批处理中的任何日志事件未能发送到Kinesis流(带有错误代码返回),则日志处理器Lambda将使用指数退避和抖动算法来尝试将失败的日志事件重新发送到Kinesis流。这使并发日志处理器能够在不同时间重新发送日志事件。
其保留的并发执行(一次可以运行多少并发Lambdas)将等于分配给Kinesis流的分片数。这样可以避免向Kinesis流写入比它可以处理的数据更多的数据,还能让我们直接控制数据流入Kinesis流的速度,这意味着数据将落后于实时交付,而不是完全丢失。
失败的日志处理器
为了解释上述日志处理器的潜在故障,任何失败的日志事件批次(已重试两次但仍然失败)将被保存到死信队列中(DLQ)。
在非高峰时段每天一次,CloudWatch规则将触发失败的日志处理器。这个单独的Lambda将向DLQ询问任何失败的日志事件,并通过日志处理器重新处理它们。
为了避免超时和长时间的运行,失败的日志处理器将能够异步地重新调用自身以继续重新处理失败的日志事件,假设有更多失败的日志事件可用。
架构解决方案概述
根据我们的体系结构组件的计划,我们可以转向如何利用它们来处理日志事件并自动扩展Kinesis流。
关键指标
如前所述,扩展Lambda将使用警报来监控Kinesis指标,以查看它是否超过计算的阈值。
建议的方法是在5分钟内从关联的Kinesis流中测量IncomingRecords或IncomingBytes的总和。这可以让我们直接了解流入流中的数据量并做出有关扩展的明智决策。
门限计算
选择上述推荐指标之一后,我们可以继续计算我们想要监控的阈值。
对于具有n个分片的Kinesis流,Lambda将扩展到最多n个调用(由其保留的并发执行控制)。
每个Lambda每秒向Kinesis流发送平均m条记录。警报监视度量总和的时间是s秒。
因此,监视的阈值是n * m * s。
为确保在数据落后之前进行扩展,我们可以监控计算阈值的百分比。由于AWS的80%被认为是最佳实践,我们将继续监控该值。
架构
由于两个堆栈都是独立且通用的,因此它们可以单独部署或串联部署。当两者都部署为针对相同的Kinesis流时,结果是我们开始的问题的解决方案。
验证结果
当为我们的某个应用程序部署架构时,我们需要验证我们的数据是否实时可用,并且在需要时进行扩展。
首先,我们可以比较转发到日志处理器Lambda的日志事件数量与使用CloudWatch写入Kinesis流的记录数量,以确保数据不会落后。
转发到日志处理器的日志事件总和等于每个数据点发送给Kinesis的记录总和。这意味着处理后的数据可以实时获得!
最后,我们可以使用Grafana将我们报告的自定义指标与并发日志处理器Lambda的平均数量进行可视化。
一旦超过设定的阈值就会发生放大,而在非高峰时段的设定时间开始按比例缩小并持续到结束。并发日志处理器Lambdas的平均数量也从未超过并发限制。这证实了我们正在自动扩展Kinesis流!
结论
我们已经成功开发了一个解决方案架构,其中包含两个可重复使用的CloudFormation模板,可以单独部署或者联合部署。
日志处理模板使我们能够以最小的努力一般地转换数据。围绕CloudWatch日志和Kinesis的所有样板代码都在后台处理。这使团队可以专注于如何转换数据。
自动缩放模板使我们能够定义Kinesis流安全放大和缩小的时间和方式。Kinesis流不再需要过度配置,以避免突然出现尖峰。这最大限度地减少了人工干预并降低了总体成本。
当这两个模板一起部署时,我们还可以控制将日志事件流转换为Kinesis流的速度。如果突然出现峰值,数据将暂时落后于实时交付,直到扩大规模完成为止。这比稍后重试失败的日志事件批要好得多,因为它将日志事件完全删除或多次处理的概率降到最低。
总的来说,构建这个解决方案架构非常有趣!虽然它最初是为API服务的用例开发的,但我很高兴我们将架构概括为两个独立的堆栈。这将使迪士尼流媒体服务的其他团队能够利用这两个模板并为体系架构做出改进。