为微服务扩展 Kafka

时间:2021-05-18 08:35:44

标签: apache-kafka microservices scalability event-driven-design

问题

我想了解如何设计使微服务保持静止的消息传递 弹性和可扩展性。

目标

  • 微服务允许弹性数量的实例根据当前负载自动扩展和缩减。这个特性不应该被Kafka限制。
  • 我们需要保证至少一次交付
  • 我们需要保证同一实体事件的传递顺序

运行示例

  • 简单来说,假设有 2 个微服务 A 和 B;
  • A1、A2 是微服务 A 的实例;微服务 B 的 B1 和 B2 实例
  • A1 和 A2 发布描述对 A 的实体进行 CRUD 操作的事件,例如实体的创建、更新、删除。
<打击>

设计一

  • A1 在主题 a.entity.created 下发布事件,包括在消息正文中创建的实体的 id 等信息。
  • A1 必须指定将有多少个分区 (p) 以允许消费者并行消费。这将允许可扩展性。
  • B1 和 B2 作为消费者组 a.entity.created 订阅主题 b-consumers。这会导致 B 实例之间的负载分布。

问题

  • a) 与同一实体相关的事件可能会并行处理,并且可能会出现乱序,对吗?
  • b) 这将导致 B 的实例并行处理请求。限制因素是生产者如何定义 p(分区数量)。如果有 5 个分区,但我需要 8 个消费者来应对负载,那么它将无法工作,因为 3 个消费者不会收到事件。我理解正确吗?这将使 IMO 无法用于可能想要进一步扩展的弹性微服务。

设计二

  • A1 在主题 a.entity.created.{entityId} 下发布事件,导致许多不同的主题。
  • 每个分区大小设置为 1。
  • B1 和 B2 使用通配符作为消费者组 a.entity.created.* 订阅主题 b-consumers。这会导致 B 实例之间的负载分布。

问题

  • c) 由于只有一个分区,因此应该保证有关同一实体的事件按顺序传递,对吗?
  • d) 这里是如何处理可扩展性的?分区的数量不应该限制消费者的数量,或者是吗?
  • e) 是否有更好的方法来保证上述目标?

设计 III(感谢 StuartLC)

  • A1 根据 entityId 在主题 a.entity.createdpartition key 下发布事件。
  • 每个分区大小设置为 10。
  • B1 和 B2 作为消费者组 a.entity.created 订阅主题 b-consumers。这会导致 B 的实例之间的负载分布。由于分区键,关于同一实体的事件将按顺序传递。

问题

  • f) 当 p=10 时,我最多可以有 10 个消费者。这意味着如果使用环境变量,我必须在设计时/部署时估计消费者的数量。我能否将其移至运行时以便动态调整?

1 个答案:

答案 0 :(得分:4)

您不需要为每个实体设置单独的主题来确保消息的传递顺序。

相反,根据您的实体 ID(或实体的其他不可变标识符)为每条消息分配一个 partition key,以确保有关同一实体的事件始终传递到每个主题的同一分区。

>

即使多个生产者实例为同一实体发布消息,分区上消息的时间顺序通常也会保留(例如,如果 A1 和 A2 都发布实体 E1 的消息,则 E1 的分区键将确保所有 E1消息被传送到同一个分区,P1。)。在某些边缘情况下,不会保留排序(例如,生产者失去连接),在这种情况下,您可以查看 enabling idempotence

你是对的,在任何时候,一个消费者组中最多有一个消费者会订阅一个主题分区,尽管一个消费者可以被分配到多个分区。所以例如消费者 B2 可能会处理来自分区 P1(按顺序)以及来自另一个分区的所有消息。如果一个消费者死亡,那么另一个消费者将被分配到该分区(转换可能需要几秒钟)。

当在消息上提供分区键时,默认情况下,分区分配的消息是基于分区键的散列完成的。在极少数情况下(例如,实体分区键很少),这可能会导致消息在分区上分布不均匀,在这种情况下,如果您发现吞吐量受到不平衡的影响,您可以提供自己的 partitioning strategy。< /p>

基于上述,在 configuring an appropriate number of partitions 对于您的场景之后,您应该能够使用一致的分区键来满足您的设计目标,而根本不需要对 Kafka 进行过多的自定义。