一、Kafka的特点
Kafka
最早是由 LinkedIn
公司开发一种分布式的基于发布/订阅的消息系统,之后成为 Apache
的顶级项目。主要特点如下:
- 同时为发布和订阅提供高吞吐量
Kafka
的设计目标是以时间复杂度为 O(1) 的方式提供消息持久化能力,即使对TB
级以上数据也能保证常数时间的访问性能。即使在非常廉价的商用机器上也能做到单机支持每秒100K
条消息的传输。 - 消息持久化
将消息持久化到磁盘,因此可用于批量消费,例如ETL
以及实时应用程序。通过将数据持久化到硬盘以及replication
防止数据丢失。 - 分布式
支持 Server 间的消息分区及分布式消费,同时保证每个 partition 内的消息顺序传输。这样易于向外扩展,所有的producer、broker 和 consumer 都会有多个,均为分布式的。无需停机即可扩展机器。 - 消费消息采用
pull
模式
消息被处理的状态是在consumer
端维护,而不是由server
端维护,broker
无状态,consumer
自己保存offset
。 - 支持
online
和offline
的场景
同时支持离线数据处理和实时数据处理。
二、Kafka中的基本概念
1. Broker
Kafka
集群中的一台或多台服务器统称为 Broker
。
2. Topic
每条发布到 Kafka
的消息都有一个类别,这个类别被称为 Topic
。(物理上不同 Topic
的消息分开存储。逻辑上一个 Topic
的消息虽然保存于一个或多个broker
上,但用户只需指定消息的 Topic
即可生产或消费数据而不必关心数据存于何处)。
3. Partition
Topic
物理上的分组,一个 Topic
可以分为多个 Partition
,每个 Partition
是一个有序的队列。Partition
中的每条消息都会被分配一个有序的 id
(offset
)
4. Producer
消息和数据的生产者,可以理解为往 Kafka
发消息的客户端
5. Consumer
消息和数据的消费者,可以理解为从 Kafka
取消息的客户端
6. Consumer Group
每个 Consumer
属于一个特定的 Consumer Group
(可为每个 Consumer
指定Group Name
,若不指定 Group Name
则属于默认的 Group
)。 这是 Kafka
用来实现一个 Topic
消息的广播(发给所有的 Consumer
)和单播(发给任意一个 Consumer
)的手段。一个 Topic
可以有多个 Consumer
Group
。Topic
的消息会复制(不是真的复制,是概念上的)到所有的 Consumer Group
,但每个 Consumer Group
只会把消息发给该 Consumer Group
中的一个 Consumer
。如果要实现广播,只要每个 Consumer
有一个独立的 Consumer Group
就可以了。如果要实现单播只要所有的 Consumer
在同一个 Consumer Group
。用 Consumer Group
还可以将 Consumer
进行自由的分组而不需要多次发送消息到不同的 Topic
。
三、安装kafka
3.1 下载软件包
下载 Kafka Binary
软件包。
#下载
[root@iz2ze0j4s19xhxuqg75l0zz kafka]# wget http://mirrors.tuna.tsinghua.edu.cn/apache/kafka/2.3.1/kafka_2.12-2.3.1.tgz
#解压
[root@iz2ze0j4s19xhxuqg75l0zz kafka]# tar -zxvf kafka_2.12-2.3.1.tgz
[root@iz2ze0j4s19xhxuqg75l0zz kafka]# ll
total 184
drwxr-xr-x 3 root root 4096 Dec 23 23:14 bin # 执行脚本
drwxr-xr-x 2 root root 4096 Dec 23 23:09 config # 配置文件
drwxr-xr-x 2 root root 4096 Dec 24 08:16 data
drwxr-xr-x 2 root root 4096 Dec 23 21:27 libs # Kafka jar 包
-rw-r--r-- 1 root root 32216 Oct 18 2019 LICENSE
drwxr-xr-x 2 root root 4096 Dec 24 08:16 logs # 日志文件
-rw------- 1 root root 1288 Dec 23 22:58 nohup.out
-rw-r--r-- 1 root root 337 Oct 18 2019 NOTICE
drwxr-xr-x 2 root root 4096 Oct 18 2019 site-docs # 文档
3.2 配置文件
创建一个 data
目录,然后编辑 conf/server.properties
配置文件,修改数据目录为新创建的 data
目录,即 log.dirs=/usr/tool/kafka/kafka/data
。
3.3 启动 Kafka
#启动一个 Kafka Broker 服务
[root@iz2ze0j4s19xhxuqg75l0zz kafka]# bin/kafka-server-start.sh config/server.properties &
# 查看 Kafka Broker 日志。
[root@iz2ze0j4s19xhxuqg75l0zz kafka]# tail -f logs/server.log
- 默认情况下,Kafka Broker 日志文件所在地址为
logs/server.log
。如果想要自定义,可以通过config/log4j.properties
配置文件来进行修改。 - 启动内存不足,修改
bin/kafka-server-start.sh
中的启动内存大小export KAFKA_HEAP_OPTS="-Xmx256M -Xms128M"
3.3 创建 Topic
在发送和消费消息之前,我们先来创建 Topic
。我们可以使用 bin/kafka-topics.sh
脚本,来进行 Kafka Topic
的管理。
# 创建名字为 TestTopic 的 Topic 。
# @param replication-factor 参数:Topic 副本数
# @param partitions 参数:Topic 分区数
[root@iz2ze0j4s19xhxuqg75l0zz kafka]# bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic TestTopic
Created topic TestTopic.
[1]+ Killed bin/kafka-server-start.sh config/server.properties
# 查询 Topic 列表
[root@iz2ze0j4s19xhxuqg75l0zz kafka]# bin/kafka-topics.sh --list --zookeeper 127.0.0.1:2181
TestTopic
3.4 测试发送消息
通过使用 bin/kafka-console-producer.sh
脚本,实现测试发送消息。
# 执行 kafka-console-producer.sh 脚本,进入使用命令行发送消息的模式。
[root@iz2ze0j4s19xhxuqg75l0zz kafka]# bin/kafka-console-producer.sh --broker-list 127.0.0.1:9092 --topic TestTopic
# 每输入一行,敲回车,都会发送一条消息
>canying
>test
>yyyy
>^C[root@iz2ze0j4s19xhxuqg75l0zz kafka]#
- 完成发送三条测试消息后,我们使用
command + C
终止当前脚本,退出。 Kafka
连接服务器报错:Connection to node 1 (localhost/127.0.0.1:9092) could not be established
,修改配置文件config/server.properties
中的listeners=PLAINTEXT://0.0.0.0:9092
(允许外部端口连接),advertised.listeners=PLAINTEXT://本机ip地址:9092
(外部代理地址)
3.5 测试消费消息
通过使用 bin/kafka-console-consumer.sh
脚本,实现测试消费消息。
# 执行 kafka-console-consumer.sh 脚本,进入使用命令行消费消息
[root@iz2ze0j4s19xhxuqg75l0zz kafka]# bin/kafka-console-consumer.sh --bootstrap-server 127.0.0.1:9092 --topic TestTopic --from-beginning
canying
test
yyyy
3.6 删除topic
[root@iz2ze0j4s19xhxuqg75l0zz kafka]# bin/kafka-topics.sh --delete --zookeeper localhost:2181 --topic TestTopic
- 如果
kafka
启动时加载的配置文件中server.properties
没有配置delete.topic.enable=true
,那么此时的删除并不是真正的删除,而是把topic
标记为:marked for deletion
2.7 查看所有 topic
[root@iz2ze0j4s19xhxuqg75l0zz kafka]# bin/kafka-topics.sh --zookeeper localhost:2181 --list
2.8 物理删除 topic
# 登录zookeeper客户端
[root@iz2ze0j4s19xhxuqg75l0zz bin]# /usr/tool/zookeeper/zookeeper/bin/zkCli.sh
# 找到topic所在的目录
[zk: localhost:2181(CONNECTED) 0] ls /brokers/topics
[TestTopic, __consumer_offsets]
# 找到要删除的topic,即可彻底被删除
[zk: localhost:2181(CONNECTED) 1] rmr /brokers/topics/test-topic
三、Java 客户端访问
3.1 maven
工程的pom
文件中添加依赖
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>0.11.0.1</version>
</dependency>
3.2 消息生产者
public class ProducerSample {
public static void main(String[] args) {
Map<String, Object> props = new HashMap<String, Object>();
//zookeeper 的地址
props.put("zk.connect", "127.0.0.1:2181");
//用于建立与 kafka 集群连接的 host/port 组。
props.put("bootstrap.servers", "101.200.142.27:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
String topic = "test-topic";
Producer<String, String> producer = new KafkaProducer<String, String>(props);
producer.send(new ProducerRecord<String, String>(topic, "idea-key2", "java-message 1"));
producer.send(new ProducerRecord<String, String>(topic, "idea-key2", "java-message 2"));
producer.send(new ProducerRecord<String, String>(topic, "idea-key2", "java-message 3"));
producer.close();
}
}
3.3 消息消费者
public class ConsumerSample {
public static void main(String[] args) {
// topic name
String topic = "test-topic";
Properties props = new Properties();
//用于建立与 kafka 集群连接的 host/port 组。
props.put("bootstrap.servers", "127.0.0.1:9092");
// Consumer Group Name
props.put("group.id", "testGroup1");
// Consumer 的 offset 是否自动提交
props.put("enable.auto.commit", "true");
// 自动提交 offset 到 zookeeper 的时间间隔,时间是毫秒
props.put("auto.commit.interval.ms", "1000");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
Consumer<String, String> consumer = new KafkaConsumer(props);
consumer.subscribe(Arrays.asList(topic));
while (true) {
ConsumerRecords<String, String> records = consumer.poll(100);
for (ConsumerRecord<String, String> record : records) {
System.out.printf("partition = %d, offset = %d, key = %s, value = %s%n", record.partition(), record.offset(), record.key(), record.value());
}
}
}
}
3.4 启动 zookeeper
3.5 启动 kafka
服务器
3.6 运行 Consumer
先运行 Consumer
,这样当生产者发送消息的时候能在消费者后端看到消息记录。
3.7 运行 Producer
运行 Producer
,发布几条消息,在 Consumer
的控制台能看到接收的消息。
四、启动 Kafka Manager
# 下载。可能很慢,可以考虑采用迅雷下载。
wget https://github.com/wolfogre/kafka-manager-docker/releases/download/2.0.0.2/kafka-manager-2.0.0.2.zip
# 启动一个 Kafka Manager 服务
[root@iz2ze0j4s19xhxuqg75l0zz kafka-manager]# bin/kafka-manager &
# 查看 Kafka Broker 日志
[root@iz2ze0j4s19xhxuqg75l0zz kafka-manager]# tail -f logs/application.log
Application started (Prod)
2020-12-24 14:15:01,845 - [INFO] - from play.core.server.AkkaHttpServer in main
Listening for HTTP on /0:0:0:0:0:0:0:0:9000
添加kafka
集群:
- 使用浏览器,访问
http://127.0.0.1:9000/
地址,我们就可以看到 Kafka Manager 的界面。
- 点击导航栏的
Cluster
按钮,选择Add Cluster
选项,进入http://127.0.0.1:9000/addCluster
地址。在该界面,我们配置新增Kafka
集群。
五、Kafka集群配置
待续…