Apache Kafka按特定顺序使用来自不同主题的事件

时间:2019-09-23 20:51:25

标签: concurrency java-8 apache-kafka spring-kafka

比方说,我有topicA,topicB和topicC,这两个主题均基于域实体按不同的事件类型进行隔离。 topicA仅与eventA一起使用,topicB保留eventB,topicC仅与eventC一起使用。所有事件均按业务领域相互关联,但由单独的微服务产生,应按特定顺序进行处理。

问题是,如何使用Apache Kafka按特定顺序引入消耗事件,eventA然后等待接收eventB,然后当eventC接收时消耗所有事件。

感谢任何反馈,欢迎提出任何疑问。

一些注意事项: Kafka Streams是一种很好的方法,但是受公司政策的限制。

此外,我浏览了Join Pattern,但没有找到任何可靠的实现方法。

3 个答案:

答案 0 :(得分:2)

如果事件相互关联,则应转到一个主题。因此,微服务1应该使用(键,值)和标签(事件A)推送事件A。同样,microservice-2和microservice-3应该将数据推送到一个通用主题。

这将在消费者方面为您提供帮助。

答案 1 :(得分:2)

可能有很多方法可以解决此问题。这是我可以建议的几个:

  • 引入相关性ID ,它将链接来自主题A,B和C的事件。然后,按以下方式使用相关性ID:

    1. 服务A,B和C产生与相应主题相关的事件,但相关事件具有相同的相关ID

    2. 服务D使用来自不同主题的事件。每当服务D接收到来自任何主题的事件时,服务D要么通过相关ID将事件数据插入数据库,要么在接收到所有数据时执行某些操作。

    例如,当服务D接收到事件C时,它首先发出查询以检查数据库中是否有来自事件C的具有关联ID的记录:

    • 如果没有记录,则存储传入事件C,
    • 如果某些记录已经存在,则服务D检查事件C是否是消耗所有数据所需的最后一个事件,并执行最终操作,或者将事件C插入数据库。

    对于每个消耗的事件,依此类推。

  • 产生事件的链服务 (A,B和C)。例如,可以按以下方式形成链:

    1. 服务A对主题A产生事件

    2. 服务B使用主题A中的事件,并向主题B中生成事件(可能是将事件A和B聚合在一起)

    3. 服务C使用主题B中的事件,并向主题C中生成事件(可能是将事件A,B和C聚合在一起)

    4. 最后,服务D使用主题C的事件(可能与A,B和C聚合)并执行所需的操作。

    这种方法的变化(在每个中间阶段不汇总事件)将是链接服务并侦听链中的最后一个事件。当消耗了最后一个事件时,请向相应的主题发出Kafka pull,以获取其他服务产生的事件。

答案 2 :(得分:1)

由于您要询问有关在不同主题之间对消息的消费进行排序的问题,因此第一种选择是让一个消费者产生一条消息,为下一个消费者提供食物(这些消费者可能会或可能不在同一过程中):

消费者A处理消息->消费者A将新消息放在不同的主题上->消费者B拾取新消息并进行处理->消费者B将新消息放在第二个主题上->等等...等等。

如果Stream实际上是在后台进行此操作或进行类似的处理,我不会感到惊讶。可以使用任何其他类型的进程间通信接口:RDP,内存映射文件,互斥锁,管道;选择。

除非万不得已,否则我将尽量避免在同一主题上放置不同的事件。当您将多个事件放在单个队列/主题上时,会以几种方式限制消费者:

  1. 您的合同现在在两个事件中都紧密相关。要仅更改单个主题中事件之一的形状,您的使用者就必须根据元数据(幻数,键值等)动态反序列化这些事件。
  2. 您的消费模式可能效率较低。如果我只对其中一项事件感兴趣怎么办?我必须阅读该事件,然后将其丢弃(如果不是我想要的事件)。

一个现实的例子是在游乐园中。假设您有两种类型的游乐园访客:快速通过和标准顾客。您的业​​务规则规定,“快速通过”客户可以跳过标准客户之前的排队。

如果将它们合并到一个队列/主题中,该怎么做?答案是优先级排队。您问所有排队的人是否都通过快速通行,这容易出错并且效率低下(这是优先级排队;可以工作,但可能不是最佳解决方案)。大多数游乐园通过设置两个单独的队列(每种类型的客户[事件/消息]一个)来解决此问题。现在,他们可以将客户送入两个单独的服务员中(一个FastPass一个Standard),或者他们可以让一个服务员同时执行两个队列,首先清空快速通过队列。

最终,这取决于您的约束:一天是10条消息,还是10亿条,您需要即时一致性还是最终一致性?是在IoT设备上吗?