大家好,欢迎来到IT知识分享网。
作者:Kevin Lam 和 Rafael Aguiar
在 Shopify,我们采用Apache Flink作为标准的有状态流引擎,为各种用例提供支持。今年早些时候,我们分享了优化大型有状态 Flink 应用程序的技巧。下面我们将向您介绍另外 3 个最佳实践。
1.设置正确的平行度
Flink 应用程序由多个任务组成,包括转换(运算符)、数据源和接收器。这些任务被拆分成几个并行实例用于执行和数据处理。
并行性是指任务的并行实例,是一种使您能够扩展或扩展的机制。它是影响应用程序性能的主要因素之一。增加并行性允许应用程序利用更多任务槽,这可以提高整体吞吐量和性能。
可以通过几种不同的方式配置应用程序并行性,包括:
- 操作员级别
- 执行环境级别
- 客户端级别
- 系统级
配置选择实际上取决于您的 Flink 应用程序的细节。例如,如果您的应用程序中的某些运算符已知是瓶颈,您可能只想增加该瓶颈的并行度。
我们建议从单个执行环境级别的并行度值开始,并在需要时增加它。这是一个很好的起点,因为任务槽共享可以更好地利用资源。当 I/O 密集型子任务阻塞时,非 I/O 子任务可以使用任务管理器资源。
识别并行性时要遵循的一个好的规则是:
任务管理器的数量乘以每个任务管理器中的任务槽数必须等于(或略高于)最高并行度值
例如,当使用 100 的并行度(定义为默认执行环境级别或特定操作员级别)时,您将需要运行 25 个任务管理器,假设每个任务管理器有四个槽:25 x 4 = 100 。
2.避免水槽瓶颈
数据管道通常有一个或多个数据接收器(目的地如 Bigtable、Apache Kafka 等),这有时会成为 Flink 应用程序的瓶颈。例如,如果您的目标 Bigtable 实例具有高 CPU 使用率,则可能会由于 Flink 无法跟上写入流量而开始影响您的 Flink 应用程序。您可能看不到任何异常,但一直到源的吞吐量都在下降。您还会在Flink UI中看到背压。
当接收器成为瓶颈时,背压将传播到其所有上游依赖项,这可能是您的整个管道。您想确保您的水槽永远不会成为瓶颈!
在可以牺牲一点延迟的情况下,通过第一批写入接收器以支持更高的吞吐量来解决瓶颈是很有用的。批量写入请求是将多个事件收集为一个包并一次性提交给接收器的过程,而不是一次提交一个事件。批量写入通常会导致更好的压缩、更低的网络使用率和更小的 CPU 对接收器的影响。有关示例,请参见 Kafka 的batch.size属性和 Bigtable 的批量突变。
您还需要检查并修复任何数据偏差。在同一个 Bigtable 示例中,您可能有严重倾斜的键,这将影响 Bigtable 的一些最热节点。Flink 使用键控流来扩展到节点。该概念涉及根据特定键对流的事件进行分区。Flink 然后在不同的节点上处理不同的分区。
KeyBy经常用于重新键入 aDataStream 以执行聚合或连接。它非常易于使用,但如果选择的密钥分布不当,可能会导致很多问题。例如,在 Shopify,如果我们要选择一个商店 ID 作为我们的键,那将是不理想的。店铺号是我们平台上单个商户店铺的标识。不同的 shop 流量差别很大,这意味着一些 Flink 任务管理器会忙于处理数据,而其他人则闲置。这很容易导致内存不足异常和其他故障。低基数 ID(< 100)也有问题,因为很难在任务管理器之间正确分配它们。
但是,如果您绝对需要使用不太理想的密钥怎么办?那么,您可以应用分桶技术:
- 选择一个最大数(从小于或等于运算符并行度的数开始)
- 随机生成一个介于 0 和最大数之间的值
- 在 keyBy 之前将其附加到您的密钥
通过应用分桶技术,您的处理逻辑可以更好地分布(达到每个键的最大附加分桶数)。但是,您需要想出一种方法来最终组合结果。例如,如果在处理完所有存储桶后发现数据量显着减少,则可以使用原始“不太理想”的密钥对流进行 keyBy,而不会产生有问题的数据倾斜。如果您的查询引擎支持,另一种方法是在查询时合并您的结果。
3.用于 HybridSource合并异构源
假设您需要按照某种顺序将多个异构数据源抽象为一个。例如,在 Shopify,我们大量的 Flink 应用程序读取和写入 Kafka。为了节省与存储相关的成本,我们对所有 Kafka 主题实施按主题保留策略。这意味着经过一段时间后,数据将过期并从 Kafka 主题中删除。由于用户可能在过期后仍然关心这些数据,因此我们支持配置 Kafka 主题进行归档。当一个主题被归档时,该主题的所有 Kafka 数据都被复制到一个云对象存储中进行长期存储。这样可以确保它在保留期结束时不会丢失。
现在,如果我们需要我们的 Flink 应用程序读取与配置为存档的主题相关的所有数据,我们该怎么办?好吧,我们可以创建两个源——一个源用于从云存储档案中读取,一个源用于读取实时 Kafka 主题。但这会造成复杂性。通过这样做,我们的应用程序将同时从两个不同的来源读取事件时间中的两个点。最重要的是,如果我们关心按顺序处理事物,我们的 Flink 应用程序必须显式实现应用程序逻辑来正确处理。
如果您发现自己处于类似情况,请不要担心有更好的方法!您可以使用它HybridSource 来使存档和实时数据看起来像一个逻辑源。使用HybridSource,您可以为您的用户提供一个单一来源,该来源首先从云存储存档中读取一个主题,然后当存档耗尽时,自动切换到实时 Kafka 主题。应用程序开发人员只看到一个逻辑DataStream,他们不必考虑任何底层机制。他们只需阅读整个数据历史即可。
使用HybridSource读取云对象存储数据还意味着您可以利用更多的输入分区来提高读取吞吐量。虽然我们的 Kafka 主题之一可能会跨数十个或数百个分区进行分区以支持实时数据的足够吞吐量,但我们的对象存储数据集通常每次拆分(例如一天)跨数千个分区进行分区以容纳大量历史数据。出色的对象存储分区与足够多的任务管理器相结合,将使 Flink 能够快速浏览历史数据,与直接从分区较差的 Kafka 主题中读取相同数量的数据相比,可以显着减少回填时间。
DataStream下面是在 Scala 中使用我们的HybridSourcepowered创建一个的样子KafkaBackfillSource:
val stream: DataStream[KafkaEvent] =
KafkaBackfillSource.asDataStream[KafkaEvent](
"KafkaEventSource",
"topic-name",
...
)
IT知识分享网
在代码片段中,KafkaBackfillSource抽象了存档的存在(从 Kafka 主题和集群推断),以便开发人员可以将所有内容视为单个DataStream.
HybridSource是一个非常强大的构造,如果您需要 Flink 应用程序以有序格式读取多个异构数据源,则绝对应该考虑。
你去吧!优化大型有状态 Flink 应用程序的另外 3 个技巧。我们希望您喜欢我们的主要学习内容,并希望它们在您实现自己的 Flink 应用程序时有所帮助。如果您正在寻找更多提示并且还没有阅读我们的第一篇博客,请务必在此处查看它们。
作者:
Kevin Lam在生产工程部的 Streaming Capabilities 团队工作。他专注于在 Shopify 使有状态流处理变得强大和简单。在业余时间,他喜欢演奏乐器,并在厨房里尝试新食谱。
Rafael Aguiar是 Streaming Capabilities 团队的高级数据工程师。他对分布式系统和所有事物的大规模分析很感兴趣。当他不烤一些自制的比萨饼时,他可能会在户外迷路。在Linkedin上关注他。
来源:https://shopify.engineering/optimizing-apache-flink-tips-part-two
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/6282.html