Apache kafka 使用kafka流隔离消息

Apache kafka 使用kafka流隔离消息,apache-kafka,apache-kafka-streams,Apache Kafka,Apache Kafka Streams,我有一个设置,每个卡夫卡消息将包含一个发件人字段。所有这些消息都发送到一个主题 有没有办法在消费者端隔离这些信息?我希望特定于发件人的消费者能够单独阅读与该发件人相关的所有邮件 我应该使用卡夫卡流来实现这一点吗?我是卡夫卡溪的新手,任何建议和指导都会很有帮助 public class KafkaStreams3 { public static void main(String[] args) throws JSONException { Properties props

我有一个设置,每个卡夫卡消息将包含一个发件人字段。所有这些消息都发送到一个主题

有没有办法在消费者端隔离这些信息?我希望特定于发件人的消费者能够单独阅读与该发件人相关的所有邮件

我应该使用卡夫卡流来实现这一点吗?我是卡夫卡溪的新手,任何建议和指导都会很有帮助

public class KafkaStreams3 {

public static void main(String[] args) throws JSONException {       

    Properties props = new Properties();
    props.put(StreamsConfig.APPLICATION_ID_CONFIG, "kafkastreams1");
    props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");

    props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");

    final Serde < String > stringSerde = Serdes.String();

    Properties kafkaProperties = new Properties();
    kafkaProperties.put("key.serializer",
            "org.apache.kafka.common.serialization.StringSerializer");
    kafkaProperties.put("value.serializer",
            "org.apache.kafka.common.serialization.StringSerializer");

    kafkaProperties.put("bootstrap.servers", "localhost:9092");

    KafkaProducer<String, String> producer = new KafkaProducer<String, String>(kafkaProperties);



    KStreamBuilder builder = new KStreamBuilder();

   KStream<String, String> source = builder.stream(stringSerde, stringSerde, "topic1");


    KStream<String, String> s1 = source.map(new KeyValueMapper<String, String, KeyValue<String, String>>() {
        @Override
        public KeyValue<String, String> apply(String dummy, String record) {
            JSONObject jsonObject;

            try {
                jsonObject = new JSONObject(record);
                return new KeyValue<String,String>(jsonObject.get("sender").toString(), record);
            } catch (JSONException e) {
                e.printStackTrace();
                return new KeyValue<>(record, record);
            }

        }
      });

    s1.print();

    s1.foreach(new ForeachAction<String, String>() {

        @Override
        public void apply(String key, String value) {
            ProducerRecord<String, String> data1 = new ProducerRecord<String, String>(
                    key, key, value);
            producer.send(data1);

        }

    });

    KafkaStreams streams = new KafkaStreams(builder, props);

    streams.start();

    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
        @Override
        public void run() {
          streams.close();
          producer.close();
        }
      }));

}

}

我认为实现这一点的最简单方法是使用sender字段作为键,并由sender对单个主题进行分区,这将为您提供每个发件人的位置和顺序,从而为每个发件人提供更强的排序保证,并且您可以将客户端连接到特定分区进行消费

另一种可能性是,从最初的主题开始,您将消息流式传输到其他主题,然后按键聚合,这样每个发送者就有一个主题

下面是一段用于生产者的代码,然后使用json序列化程序和反序列化程序进行流式处理

制作人:

private Properties kafkaClientProperties() {
    Properties properties = new Properties();

    final Serializer<JsonNode> jsonSerializer = new JsonSerializer();

    properties.put("bootstrap.servers", config.getHost());
    properties.put("client.id", clientId);
    properties.put("key.serializer", StringSerializer.class);
    properties.put("value.serializer", jsonSerializer.getClass());

    return properties;
} 

public Future<RecordMetadata> send(String topic, String key, Object instance) {
    ObjectMapper objectMapper = new ObjectMapper();
    JsonNode jsonNode = objectMapper.convertValue(instance, JsonNode.class);
    return kafkaProducer.send(new ProducerRecord<>(topic, key,
            jsonNode));
}
溪流:

log.info("loading kafka stream configuration");
    final Serializer<JsonNode> jsonSerializer = new JsonSerializer();
    final Deserializer<JsonNode> jsonDeserializer = new JsonDeserializer();
    final Serde<JsonNode> jsonSerde = Serdes.serdeFrom(jsonSerializer, jsonDeserializer);

    KStreamBuilder kStreamBuilder = new KStreamBuilder();
    Properties props = new Properties();
    props.put(StreamsConfig.APPLICATION_ID_CONFIG, config.getStreamEnrichProduce().getId());
    props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, hosts);

    //stream from topic...
    KStream<String, JsonNode> stockQuoteRawStream = kStreamBuilder.stream(Serdes.String(), jsonSerde , config.getStockQuote().getTopic());

    Map<String, Map> exchanges = stockExchangeMaps.getExchanges();
    ObjectMapper objectMapper = new ObjectMapper();
    kafkaProducer.configure(config.getStreamEnrichProduce().getTopic());
    // - enrich stockquote with stockdetails before producing to new topic
    stockQuoteRawStream.foreach((key, jsonNode) -> {
        StockQuote stockQuote = null;
        StockDetail stockDetail;
        try {
            stockQuote = objectMapper.treeToValue(jsonNode, StockQuote.class);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        JsonNode exchangeNode = jsonNode.get("exchange");
        // get stockDetail that matches current quote being processed
        Map<String, StockDetail> stockDetailMap = exchanges.get(exchangeNode.toString().replace("\"", ""));
        stockDetail = stockDetailMap.get(key);
        stockQuote.setStockDetail(stockDetail);
        kafkaProducer.send(config.getStreamEnrichProduce().getTopic(), null, stockQuote);
    });

    return new KafkaStreams(kStreamBuilder, props);

非常感谢。我目前正在尝试第二种方法,根据发件人将其聚合到其他主题。但我觉得这是一种开销,因为我必须将它发送给发送者特定的主题,消费者必须阅读这些主题。更确切地说,我为什么不按发送者对其进行分区,或者编写单独的主题呢。流给我们带来了什么好处吗?嗨,原始主题,一个包含所有消息的主题,为您提供了一个真实来源,您拥有所有消息,以防您需要审核某些内容如果您认为某些消息丢失给客户,您可以随时从最初的消息重播并检查,另一个优点是,在发送到kafka之前对原始消息进行分组有更大的机会出现内存不足错误,从而丢失可能无法在其他任何地方持久保存的消息,最后流式传输非常优化,因此我认为您将很难使您的客户端分离比流式拆分更有效……我有这是一个示例代码,但我在执行groupByKey后仍无法确定该做什么。这给了我一个KGroupedStream。如何从中读取分组数据?如果我从您最初的问题中正确理解,您希望让每个发件人读取其完整的邮件日志,而不是仅正确读取最新的邮件日志?如果是这种情况,您不希望将Kgroup分组,您只希望根据发件人值将您的邮件从地图流式传输到不同的主题。您可以根据从JsonObject获得的发送者简单地生成一个新主题或流式传输到一个新主题。KGroupedStream和KTables用于获取特定密钥的最新条目: