获取即时Kubernetes可观察性 - 无需代理。 符合Pixie自动遥测

不要错过这个系列中的一部分:使用Apache Kafka进行新遗物的实时事件处理。这款博客系列最初发表于2018年3月。

如果你是最近的提升者Apache Kafka.,无疑是尝试通过系统来确定如何处理所有数据流。新的遗物流水费流行的流程流程大量的“事件数据“按小时为基础,所以我们已经考虑了很多问题。除非您只处理少量数据,否则您需要将数据分发到单独的分区上。

在这个系列之一 -使用Apache Kafka进行新遗物的实时事件处理- 我们解释了我们如何使用Kafka构建事件处理流的一些底层体系结构。在这篇文章中,我们解释了生产者的分区策略如何取决于您的消费者将如何处理数据。

为什么要在Kafka分区数据?

如果您有很多负载,您需要多个应用程序的实例,则需要分区数据。您的分区如何用作下游应用程序的负载均衡。Producer客户端决定了数据结束的哪个主题分区,但这是消费者应用程序对驱动决策逻辑的数据做的。如果可能,要使用的最佳分区策略是不相关/随机的。

但是,您可能需要在数据的属性上分区:

  • 主题的消费者需要通过数据的某种属性聚合
  • 消费者需要某种订购保证
  • 另一个资源是一个瓶颈,你需要拆分数据
  • 您希望专注于存储和/或索引效率的数据

第一部分,我们使用下图来说明我们运行的系统的简化,以便在事件数据上处理正在进行的查询:

流处理服务图

KAFKA数据的随机分区

我们在输入主题上使用此系统为我们最CPU密集型应用程序 - 匹配服务。这意味着匹配服务的所有实例必须知道能够匹配的所有注册查询任何事件。虽然事件卷很大,但注册查询的数量是相对地小,因此单个应用程序实例可以处理在内存中将所有它们保存在内存中。

下图使用彩色方块表示与同一查询匹配的事件。它显示了随机分配给分区的消息:

KAFKA数据的随机分区

随机分区导致消费者负荷的最甚至传播,从而使消费者更容易。它特别适用于无国籍或“令人尴尬的平行”服务。

在不手动指定分区或消息密钥时,在使用默认分区时,它会有效地获得了什么。为了获得效率提升,来自版本2.4的Kafka中的默认分区器使用“粘性”算法,将所有邮件组分组到批次的相同随机分区。

通过汇总分区

然而,在服务的主题上,您必须根据查询标识符进行分区,因为我们需要我们汇总到最终的所有事件。

此图显示与同一查询匹配的事件全部位于同一分区上。颜色代表每个事件的查询匹配:

通过聚合分区Kafka数据

在释放其服务的原始版本之后,我们发现1.5%的查询占聚合处理的大约90%的事件。正如您可以想象的那样,这导致了在不幸的分区上的一些非常糟糕的热点。

在以下示例中,您可以看到我们将聚合服务分解为两块。现在我们可以在第一阶段随机分区,在那里我们可以在其中聚合数据,然后按查询ID分区以聚合每个窗口的最终结果。这种方法允许我们大大压缩第一聚合阶段的较大流,因此它们可以在第二阶段控制加载平衡。

按时间窗口分区Kafka数据

当然,这种方法具有资源成本权衡。向Kafka写一个额外的跳跃,必须将服务分成两种意味着我们在网络和服务成本上花费更多。

在此示例中,在单个客户端上共同定位查询的所有数据也使我们能够更好地进行订购保证。

订购保证

我们通过查询标识符来分区我们的最终结果,作为从结果中消耗的客户端,我们希望按顺序提供窗口:

通过查询标识符分区Kafka数据

规划资源瓶颈和储存效率

选择分区策略时,重要的是计划资源瓶颈和存储效率。

(请注意,本节中的示例参考我一直在讨论的流式查询系统的一部分的其他服务。)

资源瓶颈:我们有另一项服务,它具有对某些已分成碎片的数据库的依赖。我们根据分片在数据库中分割的方式分区其主题。该方法产生与聚合示例的分区中的图类似的结果。每个消费者只能依赖于数据库碎片,它与之相关。因此,与其他数据库分片的问题不会影响实例或其从其分区消耗的能力。此外,如果应用程序需要在与数据库相关的内存中保持状态,则它将是一个较小的共享。当然,这种分区数据的方法也容易发生热点。

存储效率:我们查询处理系统中的源主题与永久存储事件数据的系统共享一个主题。它使用单独的消费者组在所有相同的数据中读取。有关此主题的数据是按照数据所属的客户帐户的分区。为了存储和访问效率,我们将帐户的数据集中到尽可能少的节点。虽然许多帐户足够小以适合单个节点,但某些帐户必须跨多个节点传播。如果帐户变得太大,我们有自定义逻辑将其传播跨节点,并且在需要时,我们可以缩小节点计数。

消费者分配任务

每当消费者进入或离开消费者群体时,经纪人重新平衡消费者的分区,意味着Kafka在每个应用程序实例的分区数量方面处理负载平衡。这是伟大的 - 这是Kafka的一个主要特色。我们在几乎所有服务都使用消费者群体。

默认情况下,当发生重新平衡时,所有消费者都会删除分区,并重新分配新的(称为“渴望”协议)。如果您有一个具有与消耗数据相关的状态的应用程序,例如我们的聚合器服务,则需要删除该状态并使用新分区的数据开始新鲜。

要将此分区减少在有状态服务上进行洗牌,您可以使用Stickyassignor。此分配器可以尝试将分区号保留为相同实例的分区号,只要它们留在组中,同时仍均匀地在成员跨越分区。由于分区始终在重新平衡开始时被撤销,因此如果分区移动对应用程序的逻辑很重要,则消费者客户端代码必须跟踪其是否已持续/丢失/获得的分区。这是我们用于我们的聚合服务服务的方法。

我想突出一些其他选择。来自Kafka版本2.4及更高版本,您可以使用CooperativeStickyAssignor。消费者侦听器只能在重新平衡开始时销售所有分区,而不是始终在重新平衡开始时撤消所有分区,而是在重新平衡过程中分配分配的分区中的差异。作为整个的重新平衡确实需要更长时间,并且在我们的申请中,我们需要优化分区时缩短重新平衡的时间。这就是为什么我们在铭文图案中使用“eAger”协议待在我们的聚合器服务下。然而,从Kafka版本开始,我们有能力在合作重新平衡期间从分区中消耗消耗,因此可能值得重新审视。

此外,您还可以利用静态会员资格,如果客户一致地将自己作为同一成员,则可以避免完全触发重新平衡。例如,即使底层容器重新启动,这种方法也可以使用。(经纪人和客户都必须在Kafka版本2.3或更高版本上。)

您可以直接通过消费者客户端直接分配分区,而不是触发重新平衡。当然,在这种情况下,您必须自己平衡分区,并确保消耗所有分区。我们在我们将Kafka到快照状态的情况下这样做。我们将手动关联的快照消息与我们的服务读取的输入主题的分区关联。

结论

您的分区策略将取决于您的数据的形状以及您的应用程序的处理类型。随着比较,您可能需要调整您的策略来处理数据的新卷和形状。考虑资源瓶颈在您的体系结构中,并在数据管道上相应地传播负载。它可能是CPU,数据库流量或磁盘空间,但原理是相同的。效率高,您最有限/昂贵的资源。

了解更多与Kafka合作的提示,见在规模上使用Kafka的20个最佳实践