23.Kafka(一):概述
一、Kafka概述
Kafka
是一个分布式的基于发布/订阅模式的消息队列,主要应用于大数据实时处理领域。
1.1 MQ应用场景和优缺点
https://hucheng.blog.csdn.net/article/details/102961102
1.2 消息队列的两种模式
①点对点模式(一对一,消费者主动拉取数据,消息收到后消息清除)
消息生产者生产消息发送到Queue
中,然后消息消费者从Queue
中取出并且消费消息。
消息被消费以后,Queue
中不再有存储,所以消息消费者不可能消费到已经被消费的消息。Queue
支持存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费。
②发布/订阅模式(一对多,消费者消费数据之后不会清除消息)
消息生产者(发布)将消息发布到topic
中,同时有多个消息消费者(订阅)消费该消息。和点对点方式不同,发布到topic
的消息会被所有订阅者消费。
1.3 Kafka基础架构
Provider: 消息生产者,就是向kafka broker
发消息的客户端。
Consumer: 消息消费者,向kafka broker
取消息的客户端 。
Consumer Group (CG): 消费者组由多个consumer
组成。消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一个消费者消费;消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。
Broker : 一台kafka
服务器就是一个broker
。一个集群由多个broker
组成。一个broker
可以容纳多个topic
。
Topic : 可以理解为一个队列,生产者和消费者面向的都是一个topic
;
Partition: 为了实现扩展性,一个非常大的topic
可以分布到多个broker
(即服务器)上,一个topic
可以分为多个partition
,每个partition
是一个有序的队列;
Replica: 副本,为保证集群中的某个节点发生故障时,该节点上的partition
数据不丢失,且kafka
仍然能够继续工作,kafka
提供了副本机制,一个topic
的每个分区都有若干个副本,一个leader
和若干个follower
。
leader: 每个分区多个副本的“主”,生产者发送数据的对象,以及消费者消费数据的对象都是leader
。
follower: 每个分区多个副本中的“从”,实时从leader
中同步数据,保持和leader
数据的同步。leader
发生故障时,某个follower
会成为新的leader
。
二、Kafka快速入门
2.1 安装部署
集群规划:
hadoop100 | hadoop101 | hadoop102 |
---|---|---|
zk | zk | zk |
kafka | kafka | kafka |
集群部署:
- 解压安装包
[root@hadoop100 software]# tar -zxvf kafka_2.11-0.11.0.0.tgz -C /opt/module/
- 修改解压后的文件名称
[root@hadoop100 module]# mv kafka_2.11-0.11.0.0/ kafka-0.11.0.0
- 在
kafka
目录下创建logs
文件夹
[root@hadoop100 kafka-0.11.0.0]# mkdir logs
- 修改配置文件
server.properties
- 配置环境变量
[root@hadoop100 module]# vi /etc/profile
#KAFKA_HOME
export KAFKA_HOME= /opt/module/kafka-0.11.0.2
export PATH=$PATH:$KAFKA_HOME/bin
[root@hadoop100 module]# source /etc/profile
- 分发
kafka
安装包和环境变量,并修改配置文件中broke.id
为1、2。 - 启动集群
[root@hadoop100 kafka-0.11.0.0]# bin/kafka-server-start.sh -daemon config/server.properties
[root@hadoop101 kafka-0.11.0.0]# bin/kafka-server-start.sh -daemon config/server.properties
[root@hadoop102 kafka-0.11.0.0]# bin/kafka-server-start.sh -daemon config/server.properties
- 关闭集群
[root@hadoop100 kafka-0.11.0.0]# bin/kafka-server-stop.sh stop
[root@hadoop101 kafka-0.11.0.0]# bin/kafka-server-stop.sh stop
[root@hadoop102 kafka-0.11.0.0]# bin/kafka-server-stop.sh stop
kafka
群起脚本
for i in `cat /opt/module/hadoop-2.7.2/etc/hadoop/slaves`
do
echo "========== $i =========="
ssh $i 'source /etc/profile&&/opt/module/kafka-0.11.0.2/bin/kafka-server-start.sh -daemon
/opt/module/kafka-0.11.0.2/config/server.properties &'
echo $?
done
2.2 Kafka命令行操作
- 查看当前服务器中的所有
topic
[root@hadoop100 kafka-0.11.0.0]# bin/kafka-topics.sh --zookeeper hadoop100:2181 --list
- 创建
topic
[root@hadoop100 kafka-0.11.0.0]# bin/kafka-topics.sh --zookeeper hadoop100:2181 \
--create --replication-factor 3 --partitions 1 --topic first
选项说明:
--topic
:定义topic
名
--replication-factor
:定义副本数
--partitions
:定义分区数
- 删除
topic
[root@hadoop100 kafka-0.11.0.0]# bin/kafka-topics.sh --zookeeper hadoop100:2181 \
--delete --topic first
需要server.properties
中设置delete.topic.enable=true
否则只是标记删除。
- 发送消息
[root@hadoop100 kafka-0.11.0.0]# bin/kafka-console-producer.sh \
--broker-list hadoop100:9092 --topic first
>hello
>world
- 消费消息
[root@hadoop101 kafka-0.11.0.0]# bin/kafka-console-consumer.sh \
--bootstrap-server hadoop100:9092 --from-beginning --topic first
hello
world
--from-beginning
:会把主题中以往所有的数据都读取出来。
- 查看某个
Topic
的详情
[root@hadoop100 kafka-0.11.0.0]# bin/kafka-topics.sh --zookeeper hadoop102:2181 \
--describe --topic firs
- 修改分区数(修改的分区数只能大于之前的分区数)
[root@hadoop100 kafka-0.11.0.0]# bin/kafka-topics.sh --zookeeper hadoop102:2181
--alter --topic first --partitions 6
三、Kafka架构深入
3.1 Kafka工作流程
Kafka
中消息是以topic
进行分类的,生产者生产消息,消费者消费消息,都是面向topic
的。
topic
是逻辑上的概念,而partition
是物理上的概念,每个partition
对应于一个log
文件,该log
文件中存储的就是producer
生产的数据。Producer
生产的数据会被不断追加到该log
文件末端,且每条数据都有自己的offset
。消费者组中的每个消费者,都会实时记录自己消费到了哪个offset
,以便出错恢复时,从上次的位置继续消费。
3.2 Kafka文件存储机制
由于生产者生产的消息会不断追加到log
文件末尾,为防止log
文件过大导致数据定位效率低下,Kafka
采取了分片和索引机制,将每个partition
分为多个segment
。每个segment
对应两个文件:.index
文件和.log
文件。这些文件位于一个文件夹下,该文件夹的命名规则为:topic
名称+分区序号。例如,first
这个topic
有三个分区,则其对应的文件夹为first-0
,first-1
,first-2
。
index
和log
文件以当前segment
的第一条消息的offset
命名,下图为index
文件和log
文件的结构示意图:
.index
文件存储大量的索引信息,.log
文件存储大量的数据,索引文件中的元数据指向对应数据文件中message
的物理偏移地址。
3.3 Kafka生产者
① 分区策略
分区的原因:
- 方便在集群中扩展,每个
Partition
可以通过调整以适应它所在的机器,而一个topic
又可以有多个Partition
组成,因此整个集群就可以适应任意大小的数据了; - 可以提高并发,因为可以以
Partition
为单位读写了。
分区的原则:
我们需要将producer
发送的数据封装成一个ProducerRecord
对象。
- 指明
partition
的情况下,直接将指明的值直接作为partiton
值; - 没有指明
partition
值但有key
的情况下,将key
的hash
值与topic
的partition
数进行取余得到partition
值; - 既没有
partition
值又没有key
值的情况下,第一次调用时随机生成一个整数(后面每次调用在这个整数上自增),将这个值与topic
可用的partition
总数取余得到partition
值,也就是常说的round-robin
算法。
② 数据可靠性保证
为保证producer
发送的数据,能可靠的发送到指定的topic
,topic
的每个partition
收到producer
发送的数据后,都需要向producer
发送ack
(acknowledgement
确认收到),如果producer
收到ack
,就会进行下一轮的发送,否则重新发送数据。
1.副本数据同步策略
方案 | 优点 | 缺点 |
---|---|---|
半数以上完成同步,就发送ack | 延迟低 | 选举新的leader时,容忍n台节点的故障,需要2n+1个副本 |
全部完成同步,才发送ack | 选举新的leader时,容忍n台节点的故障,需要n+1个副本 | 延迟高 |
Kafka 选择了第二种方案,原因如下: |
- 同样为了容忍
n
台节点的故障,第一种方案需要2n+1
个副本,而第二种方案只需要n+1
个副本,而Kafka
的每个分区都有大量的数据,第一种方案会造成大量数据的冗余。 - 虽然第二种方案的网络延迟会比较高,但网络延迟对
Kafka
的影响较小。
2.ISR
采用第二种方案之后,设想以下情景:leader
收到数据,所有follower
都开始同步数据,但有一个follower
,因为某种故障,迟迟不能与leader
进行同步,那leader
就要一直等下去,直到它完成同步,才能发送ack
。这个问题怎么解决呢?
Leader
维护了一个动态的in-sync replica set (ISR)
,意为和Leader
保持同步的follower
集合。当ISR
中的follower
完成数据的同步之后,leader
就会给follower
发送ack
。如果follower
长时间未向leader
同步数据,则该follower
将被踢出ISR
,该时间阈值由replica.lag.time.max.ms
参数设定。Leader
发生故障之后,就会从ISR
中选举新的leader
。
3.ack应答机制
对于某些不太重要的数据,对数据的可靠性要求不是很高,能够容忍数据的少量丢失,所以没必要等ISR
中的follower
全部接收成功。所以Kafka
为用户提供了三种可靠性级别,用户根据对可靠性和延迟的要求进行权衡,选择以下的配置。
acks
参数配置:
- 0:
producer
不等待broker
的ack
,这一操作提供了一个最低的延迟,broker
一接收到还没有写入磁盘就已经返回,当broker
故障时有可能丢失数据; - 1:
producer
等待broker
的ack
,partition
的leader
落盘成功后返回ack
。如果在follower
同步成功之前leader
故障,那么将会丢失数据;
- -1:
producer
等待broker
的ack
,partition
的leader
和follower
全部落盘成功后才返回ack
。但是如果在follower
同步完成后,broker
发送ack
之前,leader
发生故障,那么会造成数据重复。
4.故障处理细节
LEO:每个副本的最后一个offset
;
HW:所有副本中最小的LEO
。
- follower故障
follower
发生故障后会被临时踢出ISR
,待该follower
恢复后,follower
会读取本地磁盘记录的上次的HW
,并将log
文件高于HW
的部分截取掉,从HW
开始向leader
进行同步。等该follower
的LEO
大于等于该Partition
的HW
,即follower
追上leader
之后,就可以重新加入ISR
了。 - leader故障
leader
发生故障之后,会从ISR
中选出一个新的leader
,之后,为保证多个副本之间的数据一致性,其余的follower
会先将各自的log
文件高于HW
的部分截掉,然后从新的leader
同步数据。
注意:这只能保证副本之间的数据一致性,并不能保证数据不丢失或者不重复。
③ Exactly Once语义
对于某些比较重要的消息,我们需要保证exactly once
语义,即保证每条消息被发送且仅被发送一次。
在0.11
版本之后,Kafka
引入了幂等性机制(idempotent
),配合acks = -1
时的at least once
语义,实现了producer
到broker
的exactly once
语义。
idempotent
+ at least once
= exactly once
使用时,只需将enable.idempotence
属性设置为true
,kafka
自动将acks
属性设为-1。
3.4 Kafka消费者
① 消费方式
consumer
采用pull
(拉)模式从broker
中读取数据。
push
(推)模式很难适应消费速率不同的消费者,因为消息发送速率是由broker
决定的。它的目标是尽可能以最快速度传递消息,但是这样很容易造成consumer
来不及处理消息,典型的表现就是拒绝服务以及网络拥塞。而pull
模式则可以根据consumer
的消费能力以适当的速率消费消息。
pull
模式不足之处是,如果kafka
没有数据,消费者可能会陷入循环中,一直返回空数据。针对这一点,Kafka
的消费者在消费数据时会传入一个时长参数timeout
,如果当前没有数据可供消费,consumer
会等待一段时间之后再返回,这段时长即为timeout
。
② 分区分配策略
一个consumer group
中有多个consumer
,一个topic
有多个partition
,所以必然会涉及到partition
的分配问题,即确定那个partition
由哪个consumer
来消费。
Kafka
有两种分配策略,一是round robin
(轮询,默认),一是range
。range
分配是以topic
分配partition
,当有多个topic
时,可能会造成partition
分配不均匀
③ offset的维护
由于consumer
在消费过程中可能会出现断电宕机等故障,consumer
恢复后,需要从故障前的位置的继续消费,所以consumer
需要实时记录自己消费到了哪个offset
,以便故障恢复后继续消费。
Kafka 0.9
版本之前,consumer
默认将offset
保存在Zookeeper
中,从0.9
版本开始,consumer
默认将offset
保存在Kafka
一个内置的topic
中,该topic
为__consumer_offsets
。
3.5 Kafka 高效读写数据
①顺序写磁盘
Kafka
的producer
生产数据,要写入到log
文件中,写的过程是一直追加到文件末端,为顺序写。官网有数据表明,同样的磁盘,顺序写能到到600M/s
,而随机写只有100k/s
。这与磁盘的机械机构有关,顺序写之所以快,是因为其省去了大量磁头寻址的时间。
②零复制技术
3.6 Zookeeper在Kafka中的作用
Kafka
集群中有一个broker
会被选举为Controller
,负责管理集群broker
的上下线,所有topic
的分区副本分配和leader
选举等工作。Controller
的管理工作都是依赖于Zookeeper
的。
以下为partition
的leader
选举过程:
23