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

Concurrency ApacheKafka按特定顺序使用来自不同主题的事件,concurrency,java-8,apache-kafka,spring-kafka,Concurrency,Java 8,Apache Kafka,Spring Kafka,比方说,我有topicA、topicB和topicC,它们都是基于域实体,由单独的事件类型分隔的主题。topicA仅与eventA一起运行,topicB保留eventB,topicC仅与eventC一起运行。所有事件按业务域相互关联,但由单独的微服务生成,并且应按特定顺序处理 问题是,如何使用ApacheKafka按特定顺序引入消费事件,eventA然后等待接收eventB,然后在eventC接收时消费所有事件 感谢您的反馈,欢迎提出任何问题 一些注意事项: Kafka Streams是一个很好

比方说,我有topicA、topicB和topicC,它们都是基于域实体,由单独的事件类型分隔的主题。topicA仅与eventA一起运行,topicB保留eventB,topicC仅与eventC一起运行。所有事件按业务域相互关联,但由单独的微服务生成,并且应按特定顺序处理

问题是,如何使用ApacheKafka按特定顺序引入消费事件,eventA然后等待接收eventB,然后在eventC接收时消费所有事件

感谢您的反馈,欢迎提出任何问题

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


此外,我已经浏览了一遍,但没有找到任何可靠的实现方法。

如果事件彼此相关,那么它们应该转到一个主题。所以microservice-1应该使用(键、值)和标签(eventA)推送eventA。同样,microservice-2和microservice-3应该将数据推送到一个公共主题


这将在消费者方面对您有所帮助。

因为您询问的是关于在不同主题之间订购消息消费的问题,所以第一种选择是让一个消费者生成一条消息,并提供给下一个消费者(这些消费者可能是或可能不是同一过程的一部分):

consumerA处理消息->consumerA将新消息放到另一个主题->consumerB拾取新消息并处理->consumerB将新消息放到第二个主题->等等。。。等等

如果streams本质上正在做这个或类似的过程,我不会感到惊讶。可以使用任何其他类型的进程间通信接口:RDP、内存映射文件、互斥体、管道;你挑吧

除非万不得已,否则我会尽量避免把不同的事件放在同一个话题上。当您在单个队列/主题上放置多个事件时,您可以通过以下两种方式约束消费者:

  • 您的合同现在对这两个事件都是紧密耦合的。要更改单个主题上的一个事件的形状,用户必须基于元数据(幻数、键值等)动态反序列化这些事件
  • 你的消费模式可能效率较低。如果我只是对其中一个事件感兴趣呢?我必须阅读事件,然后扔掉它,如果它不是我要找的
  • 现实生活中的一个例子就是游乐园。假设您有两种类型的游乐园游客:快速通行证和标准客户。您的业务规则规定,快速通行证客户可以在标准客户之前跳过这一行

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


    归根结底,这取决于你的限制:是每天10条消息,还是10亿条消息,你需要即时一致性还是最终一致性,是在物联网设备上

    也许有很多方法可以解决这个问题。以下是我可以建议的几点:

    • 引入关联ID,该ID将链接主题A、B和C中的事件。然后,以以下方式使用关联ID:

    • 服务A、B和C生成对应主题的事件,但相关事件具有相同的关联ID

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

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

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

    • 产生活动的连锁服务(A、B和C)。例如,链可以以下列方式形成:

    • 服务A生成主题A的事件

    • 服务B使用来自主题A的事件,并生成到主题B的事件(可能是聚合事件A和B)

    • 服务C使用来自主题B的事件,并生成到主题C的事件(可能是聚合事件A、B和C)

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

    • 这种方法的变体(不在每个中间阶段聚合事件)是链接服务并侦听链中的最后一个事件。当消耗最后一个事件时,向相应的主题发出Kafka pull以获取由其他服务生成的事件


    马丁·克莱普曼(Martin Kleppmann)在这方面有一篇很棒的文章:我很好奇这些“公司政策”是什么,允许您使用生产者/消费者API,但不允许Streams@SeyedMortezaMousavi谢谢你的精彩文章。我对卡夫卡和微服务在生产中的使用经验不多,但在生产中使用卡夫卡的做法是什么,我的意思是每个企业实体都有几十个主题可以吗,或者每个人都保留少量的主题?检查以了解如何选择主题和分区的数量。Streams确实在为有状态操作这样做Streams确实是合适的