一,Kafka Stream简介
Kafka Streams。Apache Kafka开源项目的一个组成部分。是一个功能强大,易于使用的库。用于在Kafka上构建高可分布式、拓展性,容错的应用程序。它建立在流处理的一系列重要功能基础之上,比如正确区分事件事件和处理时间,处理迟到数据以及高效的应用程序状态管理。总而言之,Kafka Stream 并不是像Hadoop spark等一样的框架,而仅仅是一个类库而已。
二,Kafka Stream常用API
1,builder.stream(String topic, Consumed<K, V> consumed)
用于读取kafka里的数据。
2,
builder.addStateStore()
创建容器用来存储你的数据
3,
context.getStateStore()
获取存储的数据信息
4,context().commit
提交当前的处理进度
5,
context.getStateStore()
获取存储的数据信息(存储本地的)
三,Kafka Stream类库的基础知识
1,process方法:每读取到一条数据,这个方法都会执行一遍
2,punctuate方法:周期性的执行该方法,周期时间在init方法中调用schedule方法设置。
3,Kstream:事件流,数据的记录的方式是追加(insert),后面的数据会追加到之前的数据里。可以理解为你的Kafka Stream读取topic数据时,就是存储在这 里的。
4,Ktable:changelog流,数据的记录的方式是更新(update),相同的key后面的数据会覆盖掉前面的数据。
PS:由于Kstream和Ktable这两种特性,我们可以知道Kstream是不安全的,因为一旦日志数据出现压缩了,之前的key值就被删除了。这样进入的数据方式就变成了更新。
四,程序的代码框架
第一部分,拓扑(Topology)
整个框架的程序的入口,main方法也是写在这里。
第二部分,processor
相当于storm中的spout和bolt角色。
第三部分,自己的实现层
具体指标的实现的地方。
ps:
1,下面是官方给出的wordcount案例,大家可以参考下(这个例子用了lambda表达式,JAVA8的新特性)
import org.apache.kafka.common.serialization.Serdes;
import org.apache.kafka.streams.KafkaStreams;
import org.apache.kafka.streams.StreamsBuilder;
import org.apache.kafka.streams.StreamsConfig;
import org.apache.kafka.streams.Topology;
import org.apache.kafka.streams.kstream.Materialized;
import org.apache.kafka.streams.kstream.Produced;
import org.apache.kafka.streams.state.KeyValueStore;
import java.util.Arrays;
import java.util.Properties;
public class WordCountApplication {
public static void main(final String[] args) throws Exception {
Properties config = new Properties();
config.put(StreamsConfig.APPLICATION_ID_CONFIG, "wordcount-application");
config.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "kafka-broker1:9092");
config.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());
config.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass());
StreamsBuilder builder = new StreamsBuilder();
KStream<String, String> textLines = builder.stream("TextLinesTopic");
KTable<String, Long> wordCounts = textLines
.flatMapValues(textLine -> Arrays.asList(textLine.toLowerCase().split("\\W+")))
.groupBy((key, word) -> word)
.count(Materialized.<String, Long, KeyValueStore<Bytes, byte[]>>as("counts-store"));
wordCounts.toStream().to("WordsWithCountsTopic", Produced.with(Serdes.String(), Serdes.Long()));
KafkaStreams streams = new KafkaStreams(builder.build(), config);
streams.start();
}
}
2,下面这个是以Kafka Stream的processor方式计算wordcount的代码
public class WordCountProcessor implements Processor<String, String> {
private ProcessorContext context;
private KeyValueStore<String, Integer> kvStore;
@SuppressWarnings("unchecked")
@Override
public void init(ProcessorContext context) {
this.context = context;
this.context.schedule(1000);
this.kvStore = (KeyValueStore<String, Integer>) context.getStateStore("Counts");
}
@Override
public void process(String key, String value) {
Stream.of(value.toLowerCase().split(" ")).forEach((String word) -> {
Optional<Integer> counts = Optional.ofNullable(kvStore.get(word));
int count = counts.map(wordcount -> wordcount + 1).orElse(1);
kvStore.put(word, count);
});
}
@Override
public void punctuate(long timestamp) {
KeyValueIterator<String, Integer> iterator = this.kvStore.all();
iterator.forEachRemaining(entry -> {
context.forward(entry.key, entry.value);
this.kvStore.delete(entry.key);
});
context.commit();
}
@Override
public void close() {
this.kvStore.close();
}
}