Kafka Streams与Spring Boot

时间:2018-08-07 18:12:52

标签: spring-boot apache-kafka apache-kafka-streams spring-kafka

嘿,我想在我的Spring Boot项目中使用Kafka Streams实时处理。因此,我需要配置Kafka Streams,或者我想使用KStreams或KTable,但是在Internet上找不到示例。

我现在想制作实时流媒体,所以制作了生产者和消费者。

5 个答案:

答案 0 :(得分:12)

首先让我说,如果您不熟悉Kafka流,则在其上添加spring-boot会增加另一个层次的复杂性,并且Kafka流本身具有很大的学习曲线。以下是帮助您入门的基础知识: pom:

 <!-- https://mvnrepository.com/artifact/org.springframework.kafka/spring-kafka -->
    <dependency>
      <groupId>org.springframework.kafka</groupId>
      <artifactId>spring-kafka</artifactId>
      <version>2.1.10.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.apache.kafka/kafka-clients -->
    <dependency>
      <groupId>org.apache.kafka</groupId>
      <artifactId>kafka-clients</artifactId>
      <version>${kafka.version}</version>
    </dependency>


    <!-- https://mvnrepository.com/artifact/org.apache.kafka/kafka -->
    <dependency>
      <groupId>org.apache.kafka</groupId>
      <artifactId>kafka_2.12</artifactId>
      <version>${kafka.version}</version>
    </dependency>


    <!-- https://mvnrepository.com/artifact/org.apache.kafka/kafka-streams -->
    <dependency>
      <groupId>org.apache.kafka</groupId>
      <artifactId>kafka-streams</artifactId>
      <version>${kafka.version}</version>
    </dependency>


    <!--&lt;!&ndash; https://mvnrepository.com/artifact/org.apache.kafka/kafka-streams &ndash;&gt;-->
    <dependency>
      <groupId>org.apache.kafka</groupId>
      <artifactId>connect-api</artifactId>
      <version>${kafka.version}</version>
    </dependency>

现在是配置对象。下面的代码假定您正在创建两个流应用程序,并且请记住每个应用程序都代表其自己的处理拓扑:

import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.common.serialization.Serdes;
import org.apache.kafka.streams.StreamsConfig;
import org.apache.kafka.streams.processor.FailOnInvalidTimestamp;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.annotation.KafkaStreamsDefaultConfiguration;
import org.springframework.kafka.core.StreamsBuilderFactoryBean;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class KafkaStreamConfig {

  @Value("${delivery-stats.stream.threads:1}")
  private int threads;

  @Value("${delivery-stats.kafka.replication-factor:1}")
  private int replicationFactor;

  @Value("${messaging.kafka-dp.brokers.url:localhost:9092}")
  private String brokersUrl;


  @Bean(name = KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME)
  public StreamsConfig kStreamsConfigs() {
    Map<String, Object> config = new HashMap<>();
    config.put(StreamsConfig.APPLICATION_ID_CONFIG, "default");
    setDefaults(config);
    return new StreamsConfig(config);
  }


  public void setDefaults(Map<String, Object> config) {
    config.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, brokersUrl);
    config.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());
    config.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass());
    config.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
    config.put(StreamsConfig.DEFAULT_TIMESTAMP_EXTRACTOR_CLASS_CONFIG, FailOnInvalidTimestamp.class);
  }

  @Bean("app1StreamBuilder")
  public StreamsBuilderFactoryBean app1StreamBuilderFactoryBean() {
    Map<String, Object> config = new HashMap<>();
    setDefaults(config);
    config.put(StreamsConfig.PROCESSING_GUARANTEE_CONFIG, StreamsConfig.EXACTLY_ONCE);
    config.put(StreamsConfig.APPLICATION_ID_CONFIG, "app1");
    config.put(StreamsConfig.COMMIT_INTERVAL_MS_CONFIG, 30000);
    config.put(StreamsConfig.NUM_STREAM_THREADS_CONFIG, threads);
    config.put(StreamsConfig.REPLICATION_FACTOR_CONFIG, replicationFactor);
    return new StreamsBuilderFactoryBean(config);

  }

  //
  @Bean("app2StreamBuilder")
  public StreamsBuilderFactoryBean app2StreamBuilderFactoryBean() {
    Map<String, Object> config = new HashMap<>();
    setDefaults(config);
    config.put(StreamsConfig.PROCESSING_GUARANTEE_CONFIG, StreamsConfig.EXACTLY_ONCE);
    config.put(StreamsConfig.APPLICATION_ID_CONFIG, "app2");
    config.put(StreamsConfig.COMMIT_INTERVAL_MS_CONFIG, 30000);
    config.put(StreamsConfig.NUM_STREAM_THREADS_CONFIG, threads);
    config.put(StreamsConfig.REPLICATION_FACTOR_CONFIG, replicationFactor);
    return new StreamsBuilderFactoryBean(config);
  }
}

现在是有趣的部分,使用streamsBuilder来构建您的应用程序(在此示例中为app1)。

import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.common.serialization.Serdes;
import org.apache.kafka.streams.KeyValue;
import org.apache.kafka.streams.StreamsBuilder;
import org.apache.kafka.streams.kstream.Consumed;
import org.apache.kafka.streams.kstream.KStream;
import org.apache.kafka.streams.kstream.Produced;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class App1 {
  @SuppressWarnings("unchecked")
  @Bean("app1StreamTopology")
  public KStream<String, Long> startProcessing(@Qualifier("app1StreamBuilder") StreamsBuilder builder) {

    final KStream<String, Long> toSquare = builder.stream("toSquare", Consumed.with(Serdes.String(), Serdes.Long()));
    toSquare.map((key, value) -> { // do something with each msg, square the values in our case
      return KeyValue.pair(key, value * value);
    }).to("squared", Produced.with(Serdes.String(), Serdes.Long())); // send downstream to another topic

    return toSquare;
  }

}

希望这会有所帮助。

答案 1 :(得分:1)

这实际上不是一个特定的问题。如果要使用Spring和Kafka Framework进行流处理,则可能需要检查spring-kafka。 有很多示例,这里有one of them。 您可以使用Kafka Native API或Spring-Kafka交付解决方案,以防您希望使用例如Spring Cloud DataFlow将该应用程序纳入更大的管道中,我建议您使用Spring-Kafka,否则仅使用原生Kafka API。

答案 2 :(得分:1)

您可以使用从头开始创建新的Spring Boot项目 https://start.spring.io/ 相应地选择必要的版本/依赖关系,并生成/下载项目。

您可以开始实现kstream api方法 (https://kafka.apache.org/10/javadoc/org/apache/kafka/streams/kstream/KStream.html

答案 3 :(得分:0)

在Spring Boot中初始化Kafka Streams应用程序的另一种方法可以找到

https://gist.github.com/itzg/e3ebfd7aec220bf0522e23a65b1296c8

此方法使用KafkaStreams Bean调用kafkaStreams.start(),可以将其馈入拓扑或StreamBuilder Bean。

答案 4 :(得分:0)

在Spring Boot上轻松启动Kafka Streams的简便方法:

  1. 使用https://start.spring.io引导您的项目。选择 Cloud Stream Apache Kafka Streams的Spring 作为依赖项。这是预配置项目模板的链接:https://start.spring.io/#!language=java&dependencies=kafka-streams,cloud-stream

  2. 在您的应用程序中定义KStream bean。例如,这是一个非常基本的消费者应用程序。它仅消耗数据并将记录从KStream记录到标准输出。

    @SpringBootApplication
    public class Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Main.class, args);
        }
    
        @Bean
        public java.util.function.Consumer<KStream<String, String>> process() {
            return stream -> stream.foreach((key, value) -> {
                System.out.println(key + ":" + value);
            });
        }
    }
    

    在此应用程序中,我们定义了单个输入绑定。 Spring将使用名称process-in-0创建该绑定,即bean函数的名称后跟-in-,后跟参数的序号位置。您可以使用此绑定名称来设置其他属性,例如主题名称。例如,spring.cloud.stream.bindings.process-in-0.destination=my-topic

    查看更多示例here-《 Spring Cloud Stream Kafka Binder参考,编程模型》部分。

  3. 配置application.yaml如下:

    spring:
      cloud:
        stream:
          bindings:
            process-in-0.destination: my-topic
          kafka:
            streams:
              binder:
                applicationId: my-app
                brokers: localhost:9092
                configuration:
                  default:
                    key:
                      serde: org.apache.kafka.common.serialization.Serdes$StringSerde
                    value:
                      serde: org.apache.kafka.common.serialization.Serdes$StringSerde