1, 搭建 Kafka 环境
本章的内容比较简单,我们将使用 Docker 快速部署一个单节点的 Kafka 或 Kafka 集群,在后面的章节中,将会使用已经部署好的 Kafka 实例做实验,然后我们通过不断地实验,逐渐了解 Kafka 的知识点以及掌握客户端的使用。
这里笔者给出了单机和集群两种部署方式,但是为了便于学习后面的章节,请以集群的方式部署 Kafka。
安装 docker-compose
使用 docker-compose 部署 Kafka 可以减少很多没必要的麻烦,一个脚本即可完成部署,省下折腾时间。
安装 docker-compose 也是挺简单的,直接下载二进制可执行文件即可。
INSTALLPATH=/usr/local/bin
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o ${INSTALLPATH}/docker-compose
sudo chmod +x ${INSTALLPATH}/docker-compose
docker-compose --version
如果系统没有映射 /usr/local/bin/ 路径,执行命令完成后,如果发现找不到 docker-compose 命令,请将文件下载到 /usr/bin,即替换 INSTALLPATH=/usr/local/bin 为 INSTALLPATH=/usr/bin。
单节点 Kafka 的部署
创建一个 docker-compose.yml 文件,文件内容如下:
---version:'3'services:zookeeper:image:confluentinc/cp-zookeeper:7.3.0container_name:zookeeperenvironment:ZOOKEEPER_CLIENT_PORT:2181ZOOKEEPER_TICK_TIME:2000broker:image:confluentinc/cp-kafka:7.3.0container_name:brokerports:# To learn about configuring Kafka for access across networks see# https://www.confluent.io/blog/kafka-client-cannot-connect-to-broker-on-aws-on-docker-etc/-"9092:9092"depends_on:-zookeeperenvironment:KAFKA_BROKER_ID:1KAFKA_ZOOKEEPER_CONNECT:'zookeeper:2181'KAFKA_LISTENER_SECURITY_PROTOCOL_MAP:PLAINTEXT:PLAINTEXT,PLAINTEXT_INTERNAL:PLAINTEXTKAFKA_ADVERTISED_LISTENERS:PLAINTEXT://192.168.3.156:9092,PLAINTEXT_INTERNAL://broker:29092KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR:1KAFKA_TRANSACTION_STATE_LOG_MIN_ISR:1KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR:1volumes:-/data/kafka/broker/logs:/opt/kafka/logs-/var/run/docker.sock:/var/run/docker.sock
请替换 PLAINTEXT://192.168.3.156 中的 IP 。
然后执行命令开始部署应用:
docker-compose up -d
接着,安装 kafdrop,这是一个 Kafka 管理界面,可以很方便地查看一些信息。
docker run -d --rm -p 9000:9000 \
-e JVM_OPTS="-Xms32M -Xmx64M" \
-e KAFKA_BROKERCONNECT=192.168.3.156:9092 \
-e SERVER_SERVLET_CONTEXTPATH="/" \
obsidiandynamics/kafdrop
Kafka 集群的部署
Kafka 集群的部署方法有很多,方法不尽相同,其中使用的配置参数(环境变量)也很多,这里笔者只给出自己在使用的快速部署参数,读者可以参阅官方文档,以便定制配置。
笔者的部署脚本中其中一些重要的环境变量说明如下:
KAFKA_BROKER_ID: 当前 Broker 实例的 id,Broker id 不能重复;
KAFKA_NUM_PARTITIONS:默认 Topic 的分区数量,默认为 1,如果设置了这个配置,自动创建的 Topic 会根据这个大小设置分区数量。
KAFKA_DEFAULT_REPLICATION_FACTOR:默认 Topic 分区的副本数;
KAFKA_ZOOKEEPER_CONNECT:Zookeeper 地址;
KAFKA_LISTENERS:Kafka Broker 实例监听的 ip;
KAFKA_ADVERTISED_LISTENERS:外部如何访问当前实例,用于 Zookeeper 监控;
创建一个 docker-compose.yml 文件,文件内容如下:
---version:'3'services:zookeeper:image:confluentinc/cp-zookeeper:7.3.0container_name:zookeeperenvironment:ZOOKEEPER_CLIENT_PORT:2181ZOOKEEPER_TICK_TIME:2000kafka1:image:confluentinc/cp-kafka:7.3.0container_name:broker1ports:-19092:9092depends_on:-zookeeperenvironment:KAFKA_BROKER_ID:1KAFKA_NUM_PARTITIONS:3KAFKA_DEFAULT_REPLICATION_FACTOR:2KAFKA_ZOOKEEPER_CONNECT:'zookeeper:2181'KAFKA_LISTENERS:PLAINTEXT://0.0.0.0:9092KAFKA_ADVERTISED_LISTENERS:PLAINTEXT://192.168.3.158:19092volumes:-/data/kafka/broker1/logs:/opt/kafka/logs-/var/run/docker.sock:/var/run/docker.sockkafka2:image:confluentinc/cp-kafka:7.3.0container_name:broker2ports:-29092:9092depends_on:-zookeeperenvironment:KAFKA_BROKER_ID:2KAFKA_NUM_PARTITIONS:3KAFKA_DEFAULT_REPLICATION_FACTOR:2KAFKA_ZOOKEEPER_CONNECT:'zookeeper:2181'KAFKA_LISTENERS:PLAINTEXT://0.0.0.0:9092KAFKA_ADVERTISED_LISTENERS:PLAINTEXT://192.168.3.158:29092volumes:-/data/kafka/broker2/logs:/opt/kafka/logs-/var/run/docker.sock:/var/run/docker.sockkafka3:image:confluentinc/cp-kafka:7.3.0container_name:broker3ports:-39092:9092depends_on:-zookeeperenvironment:KAFKA_BROKER_ID:3KAFKA_NUM_PARTITIONS:3KAFKA_DEFAULT_REPLICATION_FACTOR:2KAFKA_ZOOKEEPER_CONNECT:'zookeeper:2181'KAFKA_LISTENERS:PLAINTEXT://0.0.0.0:9092KAFKA_ADVERTISED_LISTENERS:PLAINTEXT://192.168.3.158:39092volumes:-/data/kafka/broker3/logs:/opt/kafka/logs-/var/run/docker.sock:/var/run/docker.sock
由于三个 Broker 实例都在同一个虚拟机上面,因此这里通过暴露不同的端口,避免 Broker 冲突。
然后执行命令开始部署应用:
docker-compose up -d
接着部署 kafdrop:
docker run -d --rm -p 9000:9000 \
-e JVM_OPTS="-Xms32M -Xmx64M" \
-e KAFKA_BROKERCONNECT=192.168.3.158:19092,192.168.3.158:29092,192.168.3.158:39092 \
-e SERVER_SERVLET_CONTEXTPATH="/" \
obsidiandynamics/kafdrop
现在,已经部署好了 Kafka 环境以及管理面板。
2, Kafka 概念
在本章中,笔者会介绍 Kafka 的一些基本概念,文中的内容是笔者个人理解总结,可能会有错误或其它问题,如有疑问,欢迎指出。
基本概念
一个简单的 生产消息 -> 保存到 Broker -> 消费消息 的结构图示例如下:
在这里,出现了四个对象:
生产者 Producer:产生 Message 的客户端;
消费者 Consumer :消费 Message 的客户端;
主题 Topic:逻辑上的东西;
消息 Message: 数据实体;
当然图中每一个对象本身都是很复杂的,这里为了便于学习,画了个简单的图,现在我们先从最简单的结构图开始了解这些东西。
这里的图比较简单,大概是这样的, Kafka 中有多个 Topic,Producer 可以向指定的 Topic 生产一条消息,而 Consumer 可以消费指定 Topic 的消息。
Producer 和 Consumer 都是客户端应用,只是在执行的功能上有所区分,理论上 Kafka 的客户端库都是将两者的代码写在同一个模块,例如 C# 的 confluent-kafka-dotnet,同时具有生产者和消费者的 API。
然后就是这个 Message 了,Message 主要结构是:
Key
Value
其它元数据
其中 Value 是我们自定义消息内容的地方。
关于 Message,我们这里简单了解即可,在后面的章节中会继续深入介绍。
在 Kafka 中,每个 Kafka 实例称为 Broker,每个 Broker 中可以保存多个 Topic。每个 Topic 可以划分为多个分区,每个分区保存的数据是不一样的,这些分区可以在同一个 Broker 中,也可以在散布在不同的 Broker 中。
一个 Broker 可以存储不同 Topic 的不同分区,也可以存储同一个 Topic 的不同分区。
如果一个 Topic 有多个分区,一般来说其并发量会有所提高,通过增加分区数实现集群的负载均衡,一般情况下,分区均衡需要散布在不同的 Broker 才能合理地负载均衡,不然分区都在同一个 Broker 时,瓶颈在单个机器上。
如果 Broker 的实例比较少,但是 Topic 划分了多个分区,那么这些分区会被部署到同一个 Broker 上。
主题分区可以有效提高生产者或消费者的并发量,因为将消息分别存储到不同的分区中,可以同时往多个分区推送消息,会比只向一个分区推送消息的速度快。
前面提到,每个 Message 都有 Key 和 Value,Topic 可以根据 Message 的 Key 将一个 Message 存储到不同的分区。当然,我们也可以在生产消息的时候,指定向一个分区推送消息。
分区可以提高并发,但是如果一个 Broker 挂了,数据便会丢失,怎么办?
在 Kafka 中,分区可以设置多个分区副本,这些副本跟分区并不在同一个 Broker 上,这个当 Broker 挂了后,这些分区可以利用副本在其它 Broker 上复活。
[info] 提示
在 《Kafka权威指南(第2版)》 的 21 页中,指导了如何合理设置分区数量,以及分区的优势和缺点。
关于 Kafka 脚本工具
前面介绍了 Kafka 的一些简单概念,为了更加好地了解 Kafka,我们可以利用 Kafka 的脚本做一些实验。
打开其中一个 Kafka 容器(docker exec 命令进入容器),然后执行命令查看自带的二进制脚本:
ls -lah /usr/bin/ | grep kafka
可以看到,里面有很多 CLI 工具,每种 CLI 工具说明文档可以到这里查看:
https://docs.cloudera.com/runtime/7.2.10/kafka-managing/topics/kafka-manage-basics.html
下面笔者介绍部分 CLI 工具的使用方法。
主题管理
kafka-topics 是用于主题管理的 CLI 工具,kafka-topics 提供基本操作如下所示:
操作:
--create:创建主题;
--alter:变更这个主题,修改分区数等;
--config:修改主题相关的配置;
--delete:删除该主题;
在管理主题时,我们可以设置主题配置,主题配置存储时,其格式示例为 default.replication.factor ,如果用 CLI 工具操作,那么传递的参数示例为 --replication-factor,因此我们通过不同工具操作主题时,参数名称可能不同一样。
主题的所有配置参数可以查看官方文档:
https://kafka.apache.org/090/documentation.html
kafka-topics 一些常用参数:
--partitions :分区数量,该主题划分成多少个分区;
--replication-factor:副本数量,表示每个分区一共有多少个副本;副本数量需要小于或等于 Broker 的数量;
--replica-assignment:指定副本分配方案,不能与 --partitions 或 --replication-factor 同时使用;
--list: 列出有效的主题;
--describe:查询该主题的信息信息。
下面是使用 CLI 手工创建主题的命令,创建主题时设置分区、分区副本。
kafka-topics --create --bootstrap-server 192.168.3.158:19092 \
--replication-factor 3 \
--partitions 3 \
--topic hello-topic
使用 CLI 时,可以通过 --bootstrap-server 配置连接到一个 Kafka 实例,或者通过 --zookeeper 连接到 Zookeeper,然后 CLI 自动找到 Kafka 实例执行命令。
查看主题的详细信息:
kafka-topics --describe --bootstrap-server 192.168.3.158:19092 --topic hello-topic
Topic: hello-topic TopicId: r3IlKv8BSMaaoaT4MYG8WA PartitionCount: 3 ReplicationFactor: 3 Configs:
Topic: hello-topic Partition: 0 Leader: 3 Replicas: 3,1,2 Isr: 3,1,2
Topic: hello-topic Partition: 1 Leader: 1 Replicas: 1,2,3 Isr: 1,2,3
Topic: hello-topic Partition: 2 Leader: 2 Replicas: 2,3,1 Isr: 2,3,1
可以看到,创建的分区会被均衡分布到不同的 Broker 实例中;对于 Replicas 这些东西,我们后面的章节再讨论。
也可以打开 kafdrop 查看主题的信息。
如果一个 Topic 的分区数量大于 Broker 数量呢?前面笔者已经提到,如果分区数量比较大时,部分 Broker 中会存在同一个主题的多个分区。
下面我们来实验验证一下:
kafka-topics --create --bootstrap-server 192.168.3.158:19092 \
--replication-factor 2 \
--partitions 4 \
--topic hello-topic1
可以看到,Broker 2,分到了 hello-topic1 的两个分区。