定义:
功能
应用场景
优点
缺点
实施
官网:kafka.apache.org
公司:领英LinkedIn公司基于Scala语言开发的工具
功能一:分布式流式数据实时存储:分布式消息队列系统
功能二:分布式流式计算:分布式计算:KafkaStream
定义:分布式的基于订阅发布模式的高吞吐高性能的实时消息队列系统
消息队列
基于发布和订阅
分布式
实时
最终一句话:kafka是一款基于发布和订阅模型的分布式实时消息队列软件。
应用场景:大数据实时计算的架构中,实现实时数据缓存的场景
目前只要做实时大数据,都会用到kafka或者pulsar
kafka:作为大数据架构中实时消息队列,用于存储从外部同步到的所有实时数据,供实时计算引擎进行消费数据处理
实时采集:Flume(实时采集日志)、Canal(实时采集数据库)
实时MQ:kafka
实时计算:Flink、spark structstreaming
特点
类比Hdfs
概念 | HDFS | Kafka |
---|---|---|
节点 | NameNode+DataMode:普通分布式注册架构 | Broke:公平分布式 |
对象 | 文件 | Topic |
划分 | Block块 | Partition分区 |
规则 | 按照大小:BlockSize=128M | 自己决定 |
安全 | 副本机制:默认三份 | 副本机制”:自己决定 |
Segment 的本质:对每个分区的数据进行更细的划分,用于存储kafka中的数据文件并记录索引
规则: 先写入的数据会先生成一对Segment文件,存储到一定条件以后,后面数据写入另外一对Segment文件,每个文件就叫Segment文件对
实现: 每个Segment对应三个文件
设计:为了加快数据检索的效率
Offset:
#Kafka中一条数据存储的结构
offset Key Value
功能:基于offset来指定数据的顺序,消费时候按照offset顺序来读取
消费者消费Topic分区中的数据是按照offset进行分区级别顺序消费的
怎么保证消费不丢失不重复:只要保证消费者每次按照offset的顺序消费即可
如果没有Offset
从头取一遍:数据重复
从最新的读:数据丢失
Kafka | 解释 |
---|---|
Producer | Kafka生产者,负责往Kakfa写数据的客户端 |
Consumer | Kafka消费者,负责从Kafka读取数据的客户端 |
ConsumerGroup | 消费者组,必须以消费组的形式才能消费,一个消费者组中可以包含多个消费者,任何一个消费者都必须属于某个消费者组 |
Broker | Kafka节点,每个节点叫做一个Broker |
Topic | 主题,用于区分不同的数据,实现数据分类,分布式逻辑的概念,一个Topic可以对应多个分区 |
Partition | 分区,用于实现Kafka中Topic的分布式存储,每个分区可以分布在不同节点上,每个分区可以有多份 |
Replication | 副本,用于保证Kafka中分区的数据安全,每个分区中副本个数小于等于节点个数,两种角色:Leader,Follower |
Segment | 分区文件段,用于将分区中的数据按照一定的规则进行细分,加快查询性能,由两种文件组成,.log数据文件和.index索引文件 |
KV | Kafka中写入数据也是KV结构 |
Offset | 每条数据在分区中的偏移量,第N条件数据的offset = N-1,用于保证消费者按照offset顺序消费,一致性 |
cd /export/software
rz
*解压#解压安装
tar -zxvf kafka_2.12-2.4.1.tgz -C /export/server/
cd /export/server/kafka_2.12-2.4.1/
#Kafka数据存储的位置
mkdir datas
cd /export/server/kafka_2.12-2.4.1/config
#21行:唯一的 服务端id
broker.id=1
#60行:指定kafka的日志及数据【segment【.log,.index】】存储的位置
log.dirs=/export/server/kafka_2.12-2.4.1/datas
#123行:指定zookeeper的地址
zookeeper.connect=node1:2181,node2:2181,node3:2181
#在最后添加两个配置,允许删除topic,当前kafkaServer的主机名
delete.topic.enable=true
host.name=node1
cd /export/server/
scp -r kafka_2.12-2.4.1 node2:$PWD
scp -r kafka_2.12-2.4.1 node3:$PWD
#21行:唯一的 服务端id
broker.id=2
#最后
host.name=node2
vim /etc/profile
#KAFKA_HOME
export KAFKA_HOME=/export/server/kafka_2.12-2.4.1
export PATH=:$PATH:$KAFKA_HOME/bin
source /etc/profile
start-zk-all.sh
启动kafka :只能启动当前节点
cd /export/server/kafka_2.12-2.4.1/
bin/kafka-server-start.sh config/server.properties >>/dev/null 2>&1 &
关闭kafka
bin/kafka-server-stop.sh
vim /export/server/kafka_2.12-2.4.1/bin/start-kafka.sh
#!/bin/bash
KAFKA_HOME=/export/server/kafka_2.12-2.4.1
for number in {1..3}
do
host=node${number}
echo ${host}
/usr/bin/ssh ${host} "cd ${KAFKA_HOME};source /etc/profile;export JMX_PORT=9988;${KAFKA_HOME}/bin/kafka-server-start.sh ${KAFKA_HOME}/config/server.properties >>/dev/null 2>&1 &"
echo "${host} started"
done
chmod u+x /export/server/kafka_2.12-2.4.1/bin/start-kafka.sh
vim /export/server/kafka_2.12-2.4.1/bin/stop-kafka.sh
#!/bin/bash
KAFKA_HOME=/export/server/kafka_2.12-2.4.1
for number in {1..3}
do
host=node${number}
echo ${host}
/usr/bin/ssh ${host} "cd ${KAFKA_HOME};source /etc/profile;${KAFKA_HOME}/bin/kafka-server-stop.sh"
echo "${host} stoped"
done
chmod u+x /export/server/kafka_2.12-2.4.1/bin/stop-kafka.sh
关闭之后,可能需要多等待一会,才看不到进程
kafka-topics.sh
,可以查看用法kafka-topics.sh --create --topic bigdata01 --partitions 3 --replication-factor 2 --bootstrap-server node1:9092,node2:9092,node3:9092
#如果之前安装的时候没有配置kafka的环境变量 那怎么执行?
#先cd到kafka的安装包目录下 通过相关路径去执行 也可以绝对路径执行
#探究 如果创建主题的时候 分区及副本数都不指定 报错?还是有默认值?
kafka-topics.sh --create --topic test1 --bootstrap-server node1:9092,node2:9092,node3:9092
kafka-topics.sh --describe --topic test1 --bootstrap-server node1:9092,node2:9092,node3:9092
[root@node1 ~]# kafka-topics.sh --describe --topic test1 --bootstrap-server node1:9092,node2:9092,node3:9092
Topic: test1 PartitionCount: 1 ReplicationFactor: 1
Topic: test1 Partition: 0 Leader: 2 Replicas: 2 Isr: 2
#结论:如果没有指定分区数及副本数 默认主题的只有一个分区 一个副本
#探究:副本数大于集群节点个数会如何?
kafka-topics.sh --create --topic test2 --replication-factor 5 --bootstrap-server node1:9092,node2:9092,node3:9092
#报错
Replication factor: 5 larger than available brokers: 3
#探究:分区个数大于集群节点个数会如何?
kafka-topics.sh --list -bootstrap-server node1:9092,node2:9092,node3:9092
kafka-topics.sh --describe --topic bigdata01 --bootstrap-server node1:9092,node2:9092,node3:9092
# Topic名称 分区个数 副本个数
Topic: bigdata01 PartitionCount: 3 ReplicationFactor: 2
# 分区:Topic名称 + 分区编号
Topic: bigdata01 Partition: 0 Leader: 3 Replicas: 3,1 Isr: 3,1
Topic: bigdata01 Partition: 1 Leader: 1 Replicas: 1,2 Isr: 1,2
Topic: bigdata01 Partition: 2 Leader: 2 Replicas: 2,3 Isr: 2,3
Topic:Topic名称
Partition:分区的编号,从0开始
Replicas:当前这个分区所有的副本所在的Broker的id
Isr:当前这个分区所有可用的副本所在的Broker的id
Leader:当前这个分区的Leader副本所在的Broker的id
创建
kafka-topics.sh --create --topic bigdata02 --partitions 2 --replication-factor 3 --bootstrap-server node1:9092,node2:9092,node3:9092
删除
kafka-topics.sh --delete --topic bigdata02 --bootstrap-server node1:9092,node2:9092,node3:9092
pip install kafka-python -i https://pypi.tuna.tsinghua.edu.cn/simple
# coding:utf8
from kafka import KafkaProducer
"""
TODO1:构建Kafka生产者客户端对象,并且指定生产者的配置
bootstrap_servers:指定的是服务端的地址
acks:应答机制,用于决定生产者写入数据到Kafka是同步还是异步
0:生产者生产一条数据写入Kafka,不用等待Kafka的回复,直接生产下一条【快,数据容易丢失】
1:生产者生产一条数据写入Kafka,等待Kafka确保这个分区的Leader已经写入,就返回一个ack,生产者收到ack就发送下一条【性能和安全做了权衡】
all/-1:生产者生产一条数据写入Kafka,等待Kafka确保这个分区的所有ISR副本都已经写入成功,再返回ack,生产者收到ack就发送下一条【安全,性能最差】
retries:重试机制,如果生产者长时间没有收到ack,就认为数据丢失,会重新发送一份数据写入,直到收到ack
||
应答机制+重试机制保证生产者生产数据不丢失
"""
producer = KafkaProducer(bootstrap_servers=['node1:9092', 'node2:9092', 'node3:9092'], acks=1)
"""
TODO2:实现通过生产者对象调用生产方法将数据生产写入Kafka中
方法:send:用于将数据写入Kafka
参数:
topic:指定要写入的Topic
key:指定写入的Key,决定了写入数据的分区规则
value:指定写入的Value,也就是真正需要传递的数据
"""
# 每次从0 - 9 中取一个值
for i in range(0, 10):
# 调用方法写入数据:topic、key、value
rs = producer.send(topic="bigdata01", key=f"{i}".encode("UTF-8"), value=f"itcast{i}".encode("UTF-8"))
# 调用方法写入数据:topic、value
# rs = producer.send(topic="bigdata01", value=f"itcast{i}".encode("UTF-8"))
# 调用方法写入数据:topic、key、value、partition
# rs = producer.send(topic="bigdata01", key=f"{i}".encode("UTF-8"), value=f"itcast{i}".encode("UTF-8"), partition=0)
# 获取返回结果
metadata = rs.get(timeout=10)
# 打印生产结果
print(f"数据:itcast{i} topic:{metadata.topic} partition:{metadata.partition} offset:{metadata.offset}")
"""
TODO3:生产者不是直接将数据写入Kafka,而是先放到本地一个缓存中,当缓存达到一定大小或者超过一定的时间才会真正的写入Kafka
flush:强制将本地缓存的数据提交到Kafka
"""
producer.flush()
kafka-console-consumer.sh --topic bigdata01 --bootstrap-server node1:9092,node2:9092,node3:9092
pip install kafka-python -i https://pypi.tuna.tsinghua.edu.cn/simple
# coding:utf8
from kafka import KafkaConsumer
"""
TODO:1-构建一个消费者对象,指定一些配置信息
topics:需要消费的Topic
group_id:指定当前消费者属于哪个消费者组,消费组的id
bootstrap_servers:指定服务端地址
auto_offset_reset:用于指定第一次消费从什么位置消费, earliest-最早位置,latest-最近位置
enable_auto_commit:自动提交,开启后每个消费者会自动将自己负责的分区的commitoffset提交到__consumer_offsets这个topic中
还有一个参数是提交时间间隔:自动提交是按照时间间隔自动提交,1000ms = 1s
"""
consumer = KafkaConsumer(
"bigdata01",
group_id="cg1",
bootstrap_servers=['node1:9092', 'node2:9092', 'node3:9092'],
auto_offset_reset='earliest',
enable_auto_commit=True
)
"""
TODO:2-实现消费,这是一个死循环,表示源源不断的去消费,如果没有数据数据就等待,有数据就立即消费,不停的
message:表示消费到的每一条数据
topic:当前数据所属的Topic
partition:当前数据属于这个Topic哪个分区
offset:当前数据属于这个分区的哪个offset
key:获取数据中的key
value:获取数据中的value
"""
# 不断消费Kafka中的每条数据
for message in consumer:
# 从每条数据中获取所有信息
topic = message.topic
partition = message.partition
offset = message.offset
key = message.key
value = message.value.decode("UTF-8")
# 打印每条数据的内容
print(f"Topic={topic} Partition={partition} Offset={offset} Key={key} Value={value}")
auto.offset.reset = latest | earliest
latest:默认的值,从Topic每个分区的最新的位置开始消费
earliest:从最早的位置开始消费,每个分区的offset为0开始消费
面试题:
#是否自动提交offset:true表示每个消费者将自己负责的分区下一次要消费的位置自动的写入 __consumer_offsets中
enable_auto_commit=True
关闭自动提交:
# 构建消费者对象
consumer = KafkaConsumer(
"bigdata01", # topic,必须写
group_id="cg1", # 消费者组id,必须写
bootstrap_servers=['node1:9092', 'node2:9092', 'node3:9092'],
auto_offset_reset='earliest', # 启动的时候 从`可用`的最早数据开始读取,如果不设置这个参数,上来就等新数据,已有的完全不管
enable_auto_commit=False # 如果是True,你消费后,默认1分钟会在Kafka中记录你上一次消费到哪了
)
手动提交
# 手动提交Commit Offset
consumer.commit()