Kafka

Kafka是scala写的异步处理的消息队列

kafka基础框架

kafka一个分区被多个消费者 kafka 多个消费者_kafka一个分区被多个消费者

(1)Producer :消息生产者,就是向kafka broker发消息的客户端;
(2)Consumer :消息消费者,向kafka broker取消息的客户端;
(3)Consumer Group (CG):消费者组,由多个consumer组成。消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一个消费者消费;消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。
(4)Broker :一台kafka服务器就是一个broker。一个集群由多个broker组成。一个broker可以容纳多个topic。
(5)Topic :可以理解为一个队列,生产者和消费者面向的都是一个topic;
(6)Partition:为了实现扩展性,一个非常大的topic可以分布到多个broker(即服务器)上,一个topic可以分为多个partition,每个partition是一个有序的队列;
(7)Replica:副本,为保证集群中的某个节点发生故障时,该节点上的partition数据不丢失,且kafka仍然能够继续工作,kafka提供了副本机制,一个topic的每个分区都有若干个副本,一个leader和若干个follower。
(8)leader:每个分区多个副本的“主”,生产者发送数据的对象,以及消费者消费数据的对象都是leader。
(9)follower:每个分区多个副本中的“从”,实时从leader中同步数据,保持和leader数据的同步。leader发生故障时,某个follower会成为新的leader

注意:

一个消费者对应一个或者多个分区(如果反了则会有空闲多余的消费者)

分区依靠节点broker() 工作,主从分区不能在同一个节点上,一个节点可以有多个分区

副本数不能高于节点数

每个组之间的消费完全独立

kafka消息是分区内有序,多分区无序的

Kafka快速入门

集群部署

1)解压安装包

[atguigu@hadoop102 software]$ tar -zxvf kafka_2.11-2.4.1.tgz -C /opt/module/

2)修改解压后的文件名称

[atguigu@hadoop102 module]$ mv kafka_2.11-2.4.1/ kafka

3)在/opt/module/kafka目录下创建logs文件夹

[atguigu@hadoop102 kafka]$ mkdir logs

4)修改配置文件

[atguigu@hadoop102 kafka]$ cd config/
[atguigu@hadoop102 config]$ vi server.properties
输入以下内容:
#broker的全局唯一编号,不能重复
broker.id=0
#删除topic功能使能
delete.topic.enable=true
#处理网络请求的线程数量
num.network.threads=3
#用来处理磁盘IO的现成数量
num.io.threads=8
#发送套接字的缓冲区大小
socket.send.buffer.bytes=102400
#接收套接字的缓冲区大小
socket.receive.buffer.bytes=102400
#请求套接字的缓冲区大小
socket.request.max.bytes=104857600
#kafka运行日志存放的路径
log.dirs=/opt/module/kafka/logs
#topic在当前broker上的分区个数
num.partitions=1
#用来恢复和清理data下数据的线程数量
num.recovery.threads.per.data.dir=1
#segment文件保留的最长时间,超时将被删除
log.retention.hours=168
#配置连接Zookeeper集群地址
zookeeper.connect=hadoop102:2181,hadoop103:2181,hadoop104:2181/kafka

5)配置环境变量(记得分发)

[atguigu@hadoop102 module]$ sudo vi /etc/profile.d/my_env.sh

#KAFKA_HOME
export KAFKA_HOME=/opt/module/kafka
export PATH=$PATH:$KAFKA_HOME/bin

6)分发安装包

[atguigu@hadoop102 module]$ xsync kafka/
注意:分发之后记得配置其他机器的环境变量
7)分别在hadoop103和hadoop104上修改配置文件/opt/module/kafka/config/server.properties中的broker.id=1、broker.id=2
注:broker.id不得重复

7)启动集群

依次在hadoop102、hadoop103、hadoop104节点上启动kafka
[atguigu@hadoop102 kafka]$ kafka-server-start.sh -daemon $KAFKA_HOME/config/server.properties
[atguigu@hadoop103 kafka]$ kafka-server-start.sh -daemon  $KAFKA_HOME/config/server.properties
[atguigu@hadoop104 kafka]$ kafka-server-start.sh -daemon  $KAFKA_HOME/config/server.properties

加 -daemon 表示后台运行 不加默认前台

8)关闭集群

[atguigu@hadoop102 kafka]$ bin/kafka-server-stop.sh
[atguigu@hadoop103 kafka]$ bin/kafka-server-stop.sh
[atguigu@hadoop104 kafka]$ bin/kafka-server-stop.sh

9)kafka群起脚本

for i in hadoop102 hadoop103 hadoop104
do
echo "========== $i ==========" 
ssh $i '/opt/module/kafka/bin/kafka-server-start.sh -daemon /opt/module/kafka/config/server.properties'
echo $?
done

Kafka命令行操作

1)查看当前服务器中的所有topic

[atguigu@hadoop102 kafka]$ kafka-topics.sh --list --bootstrap-server hadoop102:9092

2)创建topic

[atguigu@hadoop102 kafka]$ kafka-topics.sh --create --bootstrap-server hadoop102:9092 --topic first --partitions 2 --replication-factor 2

选项说明:
–topic 定义topic名
–replication-factor 定义副本数
–partitions 定义分区数

3)删除topic

[atguigu@hadoop102 kafka]$ bin/kafka-topics.sh --bootstrap-server hadoop102:9092 \
--delete --topic first

4)发送消息

[atguigu@hadoop102 kafka]$ bin/kafka-console-producer.sh \
--broker-list hadoop102:9092 --topic first
>hello world
>atguigu  atguigu

5)消费消息

[atguigu@hadoop103 kafka]$ bin/kafka-console-consumer.sh \
--bootstrap-server hadoop102:9092 --from-beginning --topic first

[atguigu@hadoop103 kafka]$ bin/kafka-console-consumer.sh \
--bootstrap-server hadoop102:9092 --from-beginning --topic first
--from-beginning:会把主题中以往所有的数据都读取出来。

6)查看某个Topic的详情

[atguigu@hadoop102 kafka]$ kafka-topics.sh --bootstrap-server hadoop102:9092 --describe --topic first

7)修改分区数

[atguigu@hadoop102 kafka]$bin/kafka-topics.sh --bootstrap-server hadoop102:9092 --alter --topic first --partitions 6

Kafka架构深入(重点!!!(丢不丢失数据,怎么实现的?为啥这么快?))

Kafka工作流程及文件存储机制

kafka一个分区被多个消费者 kafka 多个消费者_kafka一个分区被多个消费者_02

Kafka生产者

分区策略

1)分区的原因

(1)方便在集群中扩展

(2)可以提高并发

2)分区的原则

1)有指定按照指定

2)无指定按照Key分区

3)无Key按照轮巡

注:既没有 partition 值又没有 key 值的情况下,所有发往指定话题的records,会积攒成一个batch(达到一定大小或者两条消息间隔过长)一起发送到一个分区 。当形成新的batch,我们会随机选择一个新的分区发送

数据可靠性保证

为保证producer发送的数据,能可靠的发送到指定的topic,topic的每个partition收到producer发送的数据后,都需要向producer发送ack(acknowledgement确认收到),如果producer收到ack,就会进行下一轮的发送,否则重新发送数据

kafka一个分区被多个消费者 kafka 多个消费者_hadoop_03

1)副本数据同步策略

方案

优点

缺点

半数以上完成同步,就发送ack

延迟低

选举新的leader时,容忍n台节点的故障,需要2n+1个副本

全部完成同步,才发送ack

选举新的leader时,容忍n台节点的故障,需要n+1个副本

延迟高

2)ISR(与leader保持同步的follower集合)

采用第二种方案之后,设想以下情景:leader收到数据,所有follower都开始同步数据,但有一个follower,因为某种故障,迟迟不能与leader进行同步,那leader就要一直等下去,直到它完成同步,才能发送ack。这个问题怎么解决呢?

Leader维护了一个动态的in-sync replica set (ISR),意为和leader保持同步的follower集合。当ISR中的follower完成数据的同步之后,leader就会给producer发送ack。如果follower长时间未向leader同步数据,则该follower将被踢出ISR,该时间阈值由replica.lag.time.max.ms参数设定。Leader发生故障之后,就会从ISR中选举新的leader

3)ack应答机制

对于某些不太重要的数据,对数据的可靠性要求不是很高,能够容忍数据的少量丢失,所以没必要等ISR中的follower全部接收成功。
所以Kafka为用户提供了三种可靠性级别,用户根据对可靠性和延迟的要求进行权衡,选择以下的配置。
acks参数配置:
acks:

0:如果acks=0,那么producer根本不管写入broker的消息到底成功没有,发送一条消息出去,立马就可以发 送下一条消息,这是吞吐量最高的方式,但是可能消息都丢失了,你也不知道的,但是说实话,你如果真是那 种实时数据流分析的业务和场景,就是仅仅分析一些数据报表,丢几条数据影响不大的。会让你的发送吞吐量 会提升很多,你发送弄一个batch出,不需要等待人家leader写成功,直接就可以发送下一个batch了,吞吐量 很大的,哪怕是偶尔丢一点点数据,实时报表,折线图,饼图。

1:acks=1:只要leader写入成功,就认为消息成功了,默认给这个其实就比较合适的,还是可能会导致数据 丢失的,如果刚写入leader,leader就挂了,此时数据必然丢了,其他的follower没收到数据副本,变成leader

ask=1数据丢失案例

kafka一个分区被多个消费者 kafka 多个消费者_大数据_04

-1(all):acks=all,或者acks=-1:这个leader写入成功以后,必须等待其他ISR中的副本都写入成功,才可以返回响 应说这条消息写入成功了,此时你会收到一个回调通知。但是如果在follower同步完成后,broker发送ack之前,leader发生故障,那么会造成数据重复

ask=1数据丢失案例

kafka一个分区被多个消费者 kafka 多个消费者_kafka_05

4)故障处理细节(重点!!!!!!!)
Log文件中的HW(所有副本中最小的LEO)和LEO(每个副本的最后一个offset)

kafka一个分区被多个消费者 kafka 多个消费者_大数据_06

(1)follower故障
follower发生故障后会被临时踢出ISR,待该follower恢复后,follower会读取本地磁盘记录的上次的HW,并将log文件高于HW的部分截取掉,从HW开始向leader进行同步。等该follower的LEO大于等于该Partition的HW,即follower追上leader之后,就可以重新加入ISR了。
(2)leader故障
leader发生故障之后,会从ISR中选出一个新的leader,之后,为保证多个副本之间的数据一致性,其余的follower会先将各自的log文件高于HW的部分截掉,然后从新的leader同步数据。
注意:这只能保证副本之间的数据一致性,并不能保证数据不丢失或者不重复

Kafka消费者

消费方式

consumer采用pull(拉)模式从broker中读取数据。
push(推)模式很难适应消费速率不同的消费者,因为消息发送速率是由broker决定的。它的目标是尽可能以最快速度传递消息,但是这样很容易造成consumer来不及处理消息,典型的表现就是拒绝服务以及网络拥塞。而

pull模式则可以根据consumer的消费能力以适当的速率消费消息。
pull模式不足之处是,如果kafka没有数据,消费者可能会陷入循环中,一直返回空数据。针对这一点,Kafka的消费者在消费数据时会传入一个时长参数timeout,如果当前没有数据可供消费,consumer会等待一段时间之后再返回,这段时长即为timeout

分区分配策略

一个consumer group中有多个consumer,一个 topic有多个partition,所以必然会涉及到partition的分配问题,即确定那个partition由哪个consumer来消费。

Kafka有两种分配策略,一是roundrobin,一是range

kafka一个分区被多个消费者 kafka 多个消费者_hadoop_07

1)roundrobin(轮询或者洗牌策略)

range的优化策略,解决了负载不均衡问题,但是在引入新的消费者后容易后,分配分区容易出现慢,且占资源

2)range

分区越多越容易,容易出现负载不均衡

3)sticky

解决了roundrobin的问题

Kafka API(记记producer就行)

Producer事务

为了实现跨分区跨会话的事务,需要引入一个全局唯一的Transaction ID,并将Producer获得的PID和Transaction ID绑定。这样当Producer重启后就可以通过正在进行的Transaction ID获得原来的PID。
为了管理Transaction,Kafka引入了一个新的组件Transaction Coordinator。Producer就是通过和Transaction Coordinator交互获得Transaction ID对应的任务状态。Transaction Coordinator还负责将事务所有写入Kafka的一个内部Topic,这样即使整个服务重启,由于事务状态得到保存,进行中的事务状态可以得到恢复,从而继续进行。

Consumer事务(精准一次性消费)

上述事务机制主要是从Producer方面考虑,对于Consumer而言,事务的保证就会相对较弱,尤其时无法保证Commit的信息被精确消费。这是由于Consumer可以通过offset访问任意信息,而且不同的Segment File生命周期不同,同一事务的消息可能会出现重启后被删除的情况。
如果想完成Consumer端的精准一次性消费,那么需要kafka消费端将消费过程和提交offset过程做原子绑定。此时我们需要将kafka的offset保存到支持事务的自定义介质中(比如mysql)。这部分知识会在后续项目部分涉及。

Kafka API(理解就行)

面试问题:

Kafka的丢不丢数据?

kafka事务,多副本

Kafka怎么实现的?

Kafka为啥快?

(1)顺序读写磁盘

(2)应用Pagecache(持久化)

(3)零拷贝

Zookeeper在Kafka中的作用?

Kafka集群中有一个broker会被选举为Controller,负责管理集群broker的上下线,所有topic的分区副本分配和leader选举等工作
消费过程和提交offset过程做原子绑定。此时我们需要将kafka的offset保存到支持事务的自定义介质中(比如mysql)。这部分知识会在后续项目部分涉及。

Kafka API(理解就行)

面试问题:

Kafka的丢不丢数据?

kafka事务,多副本

Kafka怎么实现的?

Kafka为啥快?

(1)顺序读写磁盘

(2)应用Pagecache(持久化)

(3)零拷贝

Zookeeper在Kafka中的作用?

Kafka集群中有一个broker会被选举为Controller,负责管理集群broker的上下线,所有topic的分区副本分配和 leader选举等工作。Controller的管理工作都是依赖于Zookeeper的
注:参考Kafka核心原理的Kafka的集群管理机制