本文由 GodPan 发表在 ScalaCool 团队博客。java
看完上一篇,相信你们对消息系统以及Kafka的总体构成都有了初步了解,学习一个东西最好的办法,就是去使用它,今天就让咱们一块儿窥探一下Kafka,并完成本身的处女做。git
虽然咱们掌握东西要一步一步来,可是咱们在大体了解了一个东西后,会有利于咱们对它的理解和学习,因此咱们能够先来看一下一条消息从发出到最后被消息者接收到底经历了什么?github
上图简要的说明了消息在Kafka中的整个流转过程(假设已经部署好了整个Kafka系统,并建立了相应的Topic,分区等细节后续再单独讲):算法
总的来讲,怎么流程仍是比较清晰和简单的,下面就跟我一块儿来练习Kafka的基本操做,最后实现一个单词计数的小demo。shell
如下代码及相应测试在如下环境测试经过:Mac OS + JDK1.8,Linux系统应该也能跑通,Windows有兴趣的同窗能够去官网下载相应版本进行相应的测试练习。apache
Mac系统同窗可使用brew安装:bootstrap
brew install kafka
复制代码
Linux系统同窗能够从官网下载源码解压,也能够直接执行如下命令:bash
cd
mkdir test-kafka && cd test-kafka
curl -o kafka_2.11-1.0.1.tgz http://mirrors.tuna.tsinghua.edu.cn/apache/kafka/1.0.1/kafka_2.11-1.0.1.tgz
tar -xzf kafka_2.11-1.0.1.tgz
cd kafka_2.11-1.0.1
复制代码
Kafka使用Zookeeper来维护集群信息,因此这里咱们先要启动Zookeeper,Kafka与Zookeeper的相关联系跟结合后续再深刻了解,毕竟不能一口吃成一个胖子。curl
bin/zookeeper-server-start.sh config/zookeeper.properties
复制代码
接着咱们启动一个Kafka Server节点:函数
bin/kafka-server-start.sh config/server.properties
复制代码
这时候Kafka系统已经算是启动起来了。
在一切就绪以后,咱们要开始作极其重要的一步,那就是建立Topic,Topic是整个系统流转的核心,另外Topic自己也包含着不少复杂的参数,好比复制因子个数,分区个数等,这里为了从简,咱们将对应的参数都设为1,方便你们测试:
bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic kakfa-test
复制代码
其中参数的具体含义:
属性 | 功能 |
---|---|
--create | 表明建立Topic |
--zookeeper | zookeeper集群信息 |
--replication-factor | 复制因子 |
--partitions | 分区信息 |
--topic | Topic名称 |
这时候咱们已经建立好了一个叫kakfa-test的Topic了。
在有了Topic后咱们就能够向其发送消息:
bin/kafka-console-producer.sh --broker-list localhost:9092 --topic kakfa-test
复制代码
而后咱们向控制台输入一些消息:
this is my first test kafka
so good
复制代码
这时候消息已经被发布在kakfa-test这个主题上了。
如今Topic上已经有消息了,如今能够从中获取消息被消费:
bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic kafka-test --from-beginning
复制代码
这时候咱们能够在控制台看到:
this is my first test kafka
so good
复制代码
至此咱们就测试了最简单的Kafka Demo,但愿你们能本身动手去试试,虽然很简单,可是这能让你对整个Kafka流程能更熟悉。
下面咱们来利用上面的一些基本操做来实现一个简单WordCount程序,它具有如下功能:
与上文的启动同样,按照其操做便可。
bin/kafka-topics.sh --zookeeper localhost:2181 --create --topic kafka-word-count-input --partitions 1 --replication-factor 1
复制代码
bin/kafka-console-producer.sh --broker-list localhost:9092 --topic kafka-word-count-input
复制代码
这部份内容是整个例子的核心,这部分代码有Java 8+和Scala版本,我的认为流处理用函数式语法表达的更加简洁清晰,推荐你们用函数式的思惟去尝试写如下,发现本身不再想写Java匿名内部类这种语法了。
咱们先来看一个Java 8的版本:
public class WordCount {
public static void main(String[] args) throws Exception {
Properties props = new Properties();
props.put(StreamsConfig.APPLICATION_ID_CONFIG, "kafka-word-count");
props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());
props.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass());
final StreamsBuilder builder = new StreamsBuilder();
KStream<String, String> source = builder.<String, String>stream("kafka-word-count-input");
Pattern pattern = Pattern.compile("\\W+");
source
.flatMapValues(value -> Arrays.asList(pattern.split(value.toLowerCase(Locale.getDefault()))))
.groupBy((key, value) -> value)
.count(Materialized.<String, Long, KeyValueStore<Bytes, byte[]>>as("counts-store")).mapValues(value->Long.toString(value))
.toStream()
.to("kafka-word-count-output");
final KafkaStreams streams = new KafkaStreams(builder.build(), props);
streams.start();
}
}
复制代码
是否是很惊讶,用java也能写出如此简洁的代码,因此说若是有适用场景,推荐你们尝试的用函数式的思惟去写写java代码。
咱们再来看看Scala版本的:
object WordCount {
def main(args: Array[String]) {
val props: Properties = {
val p = new Properties()
p.put(StreamsConfig.APPLICATION_ID_CONFIG, "kafka-word-count")
p.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092")
p.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String.getClass)
p.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String.getClass)
p
}
val builder: StreamsBuilder = new StreamsBuilder()
val source: KStream[String, String] = builder.stream("kafka-word-count-input")
source
.flatMapValues(textLine => textLine.toLowerCase.split("\\W+").toIterable.asJava)
.groupBy((_, word) => word)
.count(Materialized.as[String, Long, KeyValueStore[Bytes, Array[Byte]]]("counts-store")).toStream.to("kafka-word-count-output")
val streams: KafkaStreams = new KafkaStreams(builder.build(), props)
streams.start()
}
}
复制代码
能够发现使用Java 8函数式风格编写的代码已经跟Scala很类似了。
不少同窗电脑上并无装sbt,因此这里演示的利用Maven构建的Java版本,具体执行步骤请参考戳这里kafka-word-count上的说明。
最后咱们启动消费者进程,并在生产者中输入一些单词,好比:
最后咱们能够在消费者进程中看到如下输出:
bin/kafka-console-consumer.sh --topic kafka-word-count-output --from-beginning --bootstrap-server localhost:9092 --property print.key=true
复制代码
本篇文章主要是讲解了Kafka的基本运行过程和一些基础操做,但这是咱们学习一个东西必不可少的一步,只有把基础扎实好,才能更深刻的去了解它,理解它为何这么设计,我在这个过程当中也遇到不少麻烦,因此仍是但愿你们可以本身动手去实践一下,最终能收获更多。