简体   繁体   English

在同一个 Kafka 主题中监听多种类型的对象

[英]Listen to multiple type of objects in the same Kafka topic

I have a use case where I would be receiving two kinds of object in the same topic.我有一个用例,我将在同一主题中接收两种 object。 The issue I am facing is that all the objects are going to the same listener.我面临的问题是所有的对象都去同一个听众。 The second listener is not being used.未使用第二个侦听器。

My listeners are similar to below我的听众类似于下面

@EnableKafka
@Service
public class consumerService {

  @KafkaListener(topic = "t", groupId = "g" containerFactory = "fooContainerFactory")
  public void consume1(Foo foo) {
     logger.info("I got : " + foo);
  }

  @KafkaListener(topic = "t", groupId = "g" containerFactory = "barContainerFactory")
  public void consume2(Bar bar) {
     logger.info("I got : " + bar);
  }

}

The container factory for Foo is below, I have a similar one for Bar. Foo 的容器工厂在下面,我有一个类似的 Bar。

@Configuration
public class MyConsumerConfig {


  @Value(value = "${kafka.bootstrapAddress}")
  private String bootstrapAddress;

  @Value(value = "${group.id}")
  private String groupId;

  public Map<String, Object> clickConsumerFactory() {
    /** Set the consumer properties here */
    Map<String, Object> props = new HashMap<>();
    props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress);
    props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
    props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
    props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);
    props.put(JsonDeserializer.TRUSTED_PACKAGES, "*");
    return props;
  }

  @Bean
  public ConcurrentKafkaListenerContainerFactory<String, Foo> clickKafkaListenerContainerFactory() {
    /** Listener factory for the class 'Foo' */
    ConcurrentKafkaListenerContainerFactory<String, Foo> factory
            = new ConcurrentKafkaListenerContainerFactory<>();
    factory.setConsumerFactory(new DefaultKafkaConsumerFactory<>(clickConsumerFactory()));
    factory.setMessageConverter(new StringJsonMessageConverter());
    factory.setErrorHandler(((exception, data) -> LOGGER.info("There was an error " + exception)));
    return factory;
  }
}

I tried using KafkaHandler but I don't know how to specify the individual container factory(for Foo: FooContainerFactory, for Bar: BarContainerFactory) I am stuck at this for a few hours.我尝试使用 KafkaHandler,但我不知道如何指定单个容器工厂(对于 Foo:FooContainerFactory,对于 Bar:BarContainerFactory)我被困了几个小时。 Can somebody tell me what should I change?有人能告诉我我应该改变什么吗?

I could be way off here.我可能会离开这里。 As i am not sure how @KafkaListener works.因为我不确定@KafkaListener 是如何工作的。 But, off the top of my head, there are chances that there is only 1 partition and the first kakfaListener is assigned to that.但是,在我的脑海中,有可能只有一个分区并且第一个 kakfaListener 被分配给它。 so, any new listeners (similar to kafka consumers) will not get assigned any partition as there is just 1 partition to begin with.因此,任何新的侦听器(类似于 kafka 消费者)都不会被分配任何分区,因为开始时只有 1 个分区。 So, the new Listeners will sit idle waiting for some partition to get assigned so that they can start reading the data.因此,新的侦听器将闲置等待分配某个分区,以便他们可以开始读取数据。

You can verify this by disabling the first KafkaListener and then running your application.您可以通过禁用第一个 KafkaListener 然后运行您的应用程序来验证这一点。 The second listener would automatically kick in.第二个听众会自动加入。

or, if your topic already has multiple partitions then, it could be happening because of the key of the message as keys can be used to send data to one partition.或者,如果您的主题已经有多个分区,则可能由于消息的键而发生这种情况,因为键可用于将数据发送到一个分区。 and your first listener is assigned to that partition.并且您的第一个侦听器被分配给该分区。

You can't do that.你不能那样做。 If the same topic contains both Foo and Bar objects;如果同一个主题同时包含 Foo 和 Bar 对象; there is no way for the framework to filter out the records that don't match.框架无法过滤掉不匹配的记录。

And, as has been said in other comments, answers, since they are both in the same group, they will each get a subset of records.而且,正如在其他评论中所说的那样,答案,因为它们都在同一个组中,所以他们每个人都会得到一个记录子集。

The simplest solution is to use two different topics.最简单的解决方案是使用两个不同的主题。

If that's not possible, you have to use a class level listener with @KafkaHandler methods, but then you need to do the conversion in the deserializer instead of the framework figuring out the type from the method parameter.如果这不可能,您必须使用带有@KafkaHandler方法的 class 级别的侦听器,但是您需要在反序列化器中进行转换,而不是框架从方法参数中找出类型。

See this answer for a link to a sample that shows how to do that.有关显示如何执行此操作的示例的链接,请参阅此答案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM