如何根据另一个主题的响应从Kafka主题中读取消息

时间:2020-02-06 08:48:09

标签: java spring-boot apache-kafka kafka-consumer-api spring-kafka

我在Kafka中有2个主题:MetaData和MasterData。 我正在使用Kafka Listners实时读取数据。有2种情况:

  1. 我必须先阅读MetaData主题,然后再阅读MasterData主题。
  2. 也有可能在MetaData主题中没有新的消息,但在MasterData主题中插入了一条消息。在这种情况下,应该继续使用MasterData主题。

蚂蚁建议如何实现这一目标?

1 个答案:

答案 0 :(得分:1)

在评论中澄清之后,这就是我所了解的,您想要实现的目标:

您有一个类似system的数据库,并且来自kafka主题的元数据用于调整表结构。然后,实际数据进入主kafka主题,然后您希望将其插入表中。换句话说:您想使用kafka定义数据的结构。

我不确定,如果这就是我所说的Kafka的常规用例,那是因为它是交换事件(即数据)的接口。您尝试做的是将系统用作定义数据结构的一种方式。但这只是我的意见。

如评论中前面所述,实际上没有办法说一个主题中没有消息。您只能说:还没有消息“还”。您“可能”可以做的是:当master主题中的消息到达时,您首先检查meta主题,如果也有消息。如果存在,则应用数据结构中的更改,然后从主主题导入消息。

另一种选择是使用Kafka Streams代替原始使用者 结合两个主题,例如join

无论如何定义数据结构,通常都可以使用诸如Avro之类的东西,它可以为您提供模式演变以及更多功能。然后编写您的应用程序以了解架构更改,然后将其相应地应用于数据库表。

更新:如何使用Kafka Streams解决

如上所述,使用Kafka Streams可能是解决您的情况的方法。让我解释一下,我在一些伪kafka流代码中的意思:

import org.apache.kafka.streams.StreamsBuilder;
import org.apache.kafka.streams.kstream.GlobalKTable;

import java.nio.charset.StandardCharsets;

/**
 * Just an incomplete Kafka Streams Code Demo to show how the problem could
 * be solved with this framework instead of using the consumers directly.
 * Kafka Streams Boilerplate code not included.
 */
public class Example {
    private static final String META_TOPIC = "meta";
    private static final String MASTER_TOPIC = "master";

    // You have to make sure, the meta data is stored under this
    // specific key in the meta topic.
    private static final byte[] META_KEY = MetaEvent.class.getName().getBytes(StandardCharsets.UTF_8);

    public static void main(String[] args) {
        new Example().createTopology();
    }

    public void createTopology() {

        final StreamsBuilder builder = new StreamsBuilder();

        final GlobalKTable<byte[], MetaEvent> metaTable = builder.globalTable(META_TOPIC);

        builder.<byte[], MasterEvent>stream(MASTER_TOPIC)
                .leftJoin(
                        metaTable,
                        (k, v) -> META_KEY,
                        MasterWithMeta::new)
                .foreach(this::handleEvent);
    }

    private void handleEvent(byte[] key, MasterWithMeta masterWithMeta) {
        // 1) check if meta has changed, if so, apply changes to database
        // 2) import master data to database
    }
}

class MasterWithMeta {
    private final MasterEvent master;
    private final MetaEvent meta;

    public MasterEvent getMaster() {
        return master;
    }

    public MetaEvent getMeta() {
        return meta;
    }

    public MasterWithMeta(MasterEvent master, MetaEvent meta) {
        this.master = master;
        this.meta = meta;
    }

    public static MasterWithMeta create(MasterEvent master, MetaEvent meta) {
        return new MasterWithMeta(master, meta);
    }
}

class MetaEvent {
    // ...
}

class MasterEvent {
    // ...
}