1、kafka消息发送的流程?
最简单来讲就是生产者consel 发送消息经过以包括Topic的kafka集群,消费者consel从这里读取消息
发送原理:
在消息发送的过程中,涉及到了两个线程——main 线程和 Sender 线程。
01:在 main 线程中创建了一个双端队列 RecordAccumulator,同时将消息发送给 RecordAccumulator默认 32m
02:Sender 线程不断从 RecordAccumulator 中拉取消息
03:Sender 将拉取到的消息 发送到 Kafka Broker
batch.size(批次):只有数据积累到batch.size(一定批次)之后,sender才会发送数据。类似于城际大巴.攒够一定人数才发车
默认16klingerms:如果数据迟迟未达到batch.size,sender等待linger.ms设置的时间到了之后就会发送数据。(如果大巴人数实在是凑不够,就设置一个等待时间,时间一到就发车)单位ms,默认值是0ms,表示没有延迟。
acks 应答机制
0: 生产者发送的数据,不需要等数据落盘应答。 效率高 安全性低
1:生产者发送过来的数据,Leader收到数据后应答。效率中 安全性中
-1:(all):生产者发送过来的数据,Leader 和 ISR 队列里面的所有节点收齐数据后应答。 -1 和 all 是等价的。效率低 安全性高
从单项流程上理解消息发送过程:
1、构建一个KafkaProducer对象(重要),初始化一些用到的组件,比如缓存区,Sender线程等
2、如果配置了拦截器,可用对发送的消息进行可定制化的拦截或更改
3、对Key,value进行序列化
4、根据传入的参数,为消息选择合适的分区(重要),具体怎么选,后面分析
5、将消息按照分区发送到RecordAccmulator暂存,消息按照每个分区进行汇总
6、后台Sender线程被触发后从RecordAccmulator里面获取消息然后构建成ClientRequest,怎么构建后面分析
7、将ClientRequest封装成NetWorkClient准备发送
8、NetWorkClient将请求放入KafkaChannel准备发送,然后执行网络IO,最后发送到kafka server
2、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。(这个副本数带上leader本身),这里副本不是备份的意思。而是保证安全性的。当一个leader挂掉以后 follower会转正,但是此时不会再进行copy副本行为。而是等下次再次启动等待之前挂掉的leader回归。如果进行了copy则会在之后造成数据的冗余。
8)leader:每个分区多个副本的“主”,生产者发送数据的对象,以及消费者消费数据的对象都是leader。
9)follower:每个分区多个副本中的“从”,实时从leader中同步数据,保持和leader数据的同步。leader发生故障时,某个follower会成为新的follower。
3、Kafka 分区的目的?
1)为了实现扩展性,便于合理使用存储资源,一个topic可以分为多个partition,每个Partition在一个Broker上存储,可以把海量的数据按照分区切割成一块一块数据存储在多台Broker上。合理控制分区的任务,可以实现负载均衡的效果。
2)提高并行度,生产者可以以分区为单位发送数据;消费者可以以分区为单位进行消费数据。
生产者发送消息的分区策略
1、默认的分区器
kafka在数据生产的时候,有一个数据分发策略。默认的情况使用DefaultPartitioner.class类。这个类中就是定义数据分发的策略。
kafka默认的分区器: org.apache.kafka.clients.producer.internals.DefaultPartitioner
2、hash分区策略
假如发送消息没有指定分区,指定了Key值,对Key进行hash,然后对分区数取模,得到哪个分区就使用哪个分区
( 没有指明partition值,但有key的情况下,将key的hash值与topic的 partition数进行取模得到partition值。 Utils.toPositive(Utils.murmur2(keyBytes)) % numPartitions)
如果 key 一直不变,同一个 key 算出来的 hash 值是个固定值。如果是固定值,这种 hash 取模就没有意义。
key1的hash值=5, key2的hash值=6 ,topic的partition数=2,那 么key1** 对应的value1写入1号分区,key2对应的value2写入0号分区
3.黏性分区策略(2.4.0之前是轮询)- 未指定分区、key
既没有partition值又没有key值的情况下,Kafka采用Sticky Partition(黏性分区器),会随机选择一个分区,并尽可能一直 使用该分区,待该分区的batch已满或者已完成,Kafka再随机选一个分区进行使用(和上一次的分区不同)。
Sticky Partitioning Strategy会随机地选择一个分区并会尽可能地坚持使用该分区——即所谓的粘住这个分区。
原因:kafka 在发送消息的时候 , 采用批处理方案 , 当达到一批后进行分送 , 但是如果一批数据中有不同分区的数据 , 就无法放置到一个批处理中, 而老版本中轮询方案 , 就会导致一批数据被分到多个小的批次中 , 从而影响效率 , 故在新版本中 , 采用这种粘性的划分策略。
例如:
第一次随机选择0号分区,等0号分区当前批次满了(默认16k)或者linger.ms设置的时间到, Kafka再随机一个分区进 行使用(如果还是0会继续随机)。
4.指定partition策略
以上两种构造都会通过DefaultPartitioner进行数据分发操作。但指定分区后,不会调用DefaultPartitioner.partition() 方法。
5.自定义分区策略
自定义分区策略 跟DefaultPartitioner实现方式一样。
1、创建一个类,实现Partitioner接口。
2、重写 partitioner中的方法,
partitioner()方法的参数说明:
参数1:topic
参数2:key值
参数3:key值字节数组
参数4:value数据
参数5:value数据的字节数组
参数6:集群对象
3、在 partitioner() 方法中编写自定义分区逻辑,返回分区编号。
4、在生产者配置信息中进行配置自定义分区:
spring.kafka.producer.properties.partitioner.class=配置类全路径
@Component
public class MyPartitioner implements Partitioner {
@Override
public int partition(String topic, Object key, byte[] keyBytes,
Object value, byte[] valueBytes, Cluster cluster) {
String msgValues = value.toString();
int partition;
if (msgValues.contains("test")){
partition = 0;
}else {
partition = 1;
}
return partition;
}
@Override
public void close() {
//Nothing to close
}
@Override
public void configure(Map<String, ?> configs) {
}
}
4、你知道 Kafka 是如何做到消息的有序性?
我们需要从2个方面看待消息有序性
1. 第一,发送端能否保证发送到服务器的消息是有序的
2. 第二,接收端能否有序的消费服务器中的数据
生产者发送的数据,单分区内可以做到有序,多分区,无法保证,除非把多个分区的数据拉到消费者端,进行排序,但这样做需要等,效率很低,还不如直接设置一个分区。
5、ISR、OSR、AR 是什么?
Kafka 分区中的所有副本(包含Leader)统称为 AR(Assigned Repllicas)。
AR = ISR + OSR
ISR,所有与leader副本保持一定程度同步的副本(包括leader副本在内)组成 ISR (In Sync Replicas)。 ISR 集合是 AR 集合的一个子集。消息会先发送到leader副本,然后follower副本才能从leader中拉取消息进行同步。如果 Follower 长时间未向 Leader 发送通信请求或同步数据,则该 Follower 将被踢出 ISR。该时间阈值由 replica.lag.time.max.ms 参数设定,默认 30s。Leader 发生故障之后,就会从 ISR 中选举新的 Leader。
OSR,表示 Follower 与 Leader 副本同步时,延迟过多的副本.
6、Kafka 在什么情况下会出现消息丢失
1.producer 配置不当
如果生产者配置中 acks
设置为 0,生产者在发送消息后不会等待任何 Broker 的确认。因此,如果消息发送失败,生产者将无法得知,导致消息丢失
2.如果生产者配置中 retries
设置得过低,可能会导致在网络抖动或 Broker 暂时不可用时,生产者无法重试发送消息,从而丢失消息。
2. Broker 故障
Leader 副本不可用:
Leader 副本在写入消息后,但在 Follower 副本同步之前发生故障,可能导致消息丢失。
建议:合理配置 min.insync.replicas
,确保 ISR 中有足够的副本确认消息。
磁盘故障:
如果 Broker 的磁盘发生故障,导致数据无法读取或写入,可能会丢失未复制的消息。
建议:使用 RAID 或其他磁盘容错机制,确保数据持久化。
3. 消费者行为
消费者提交偏移量:
如果消费者在处理消息之前或处理过程中提交了偏移量,但在处理消息时发生故障,可能导致消息未被正确处理,从而被视为已消费。
建议:在确保消息处理成功后再提交偏移量,并结合幂等处理或事务机制。
消费者组重平衡:
在消费者组发生重平衡时,如果处理中的消息在重平衡后未被正确处理,可能导致消息丢失。
建议:在处理消息时使用事务机制,确保消息的完整性。
4. 副本同步延迟
如果 Follower 副本有较长的同步延迟,可能会导致 Leader 副本在故障时丢失未同步的消息。
建议:监控副本同步延迟,确保副本同步及时。
5. 配置不合理
消息保留策略:
如果消息保留策略设置不合理,例如保留时间过短或保留大小不足,可能导致消息在未被消费前被删除。
建议:根据业务需求合理配置消息保留策略。
6. 网络问题
网络分区:
如果发生网络分区(网络隔离),可能导致生产者无法连接到 Broker,或 Broker 之间无法通信,丢失消息。
建议:使用高可靠性的网络架构,并监控网络状态。
7. Kafka 版本问题
7、怎么尽可能保证 Kafka 的可靠性
生产者配置
acks 设置为 all(-1):意味着 Leader 在返回确认或错误响应之前,会等待所有同步副本都收到消息。如果和 min.insync.replicas 参数结合起来,就可以决定在返回确认前至少有多少个副本能够收到消息,生产者会一直重试直到消息被成功提交。不过这也是最慢的做法,因为生产者在继续发送其他消息之前需要等待所有副本都收到当前的消息
增加重试次数和间隔
使用幂等性生产者:
启用幂等性(Idempotence),确保每条消息在 Broker 端只会被写入一次,避免重复消息
Broker 配置
1.确保副本数设置为 3,使用 min.insync.replicas 配置保证至少有足够的副本同步数据。
2.消费者配置:正确提交偏移量:在确保消息处理成功后再提交偏移量,避免因过早提交导致的重复消费或消息丢失。
或者手动提交偏移量,禁用自动提交,配置合理的 max.poll.records 等。
3.监控和日志分析
监控和自动故障转移:及时监控集群健康,自动化故障转移,确保服务可用性
日志保留和写入策略:合理配置日志保留时间和写入刷新频率。
4.副本管理和高可用性
合理配置副本因子:根据业务需求,合理配置副本因子(replication.factor
),通常建议设置为 3,以确保数据的冗余和可用性。
5.硬件和网络:使用可靠的存储和网络系统,避免资源瓶颈和网络延迟。
8、Kafka中如何做到数据唯一,即数据去重?
1. 启用生产者的 幂等性
数据传递语义: 精确一次(Exactly Once):对于一些非常重要的信息,比如和钱相关的数据,要求数据既不能重复也不丢失。 --幂等性和事务可以保障数据精确一次.精确一次(Exactly Once) = 幂等性 + 至少一次( ack=-1 + 分区副本数>=2 + ISR最小副本数量>=2)
2.使用事务. 幂等性只能保障服务器不挂掉的情况下,发送数据是唯一的,假如发送者服务器挂掉了,那么重启之后还是会发送重复的数据,所以需要使用事务。
3.使用 手动提交偏移量,避免因消费者失败导致重复消费。
9、生产者如何提高吞吐量?
1.批量发送:配置 batch.size 和 linger.ms,将消息批量发送。batch.size:批次大小,默认16k linger.ms:等待时间,修改为5-100ms
2.消息压缩:压缩snappy 使用合适的压缩算法(如 snappy)减少网络带宽消耗。
3.配置生产者的 acks:设置为 1 或 0 来提高吞吐量,但要考虑数据丢失的风险。
4. RecordAccumulator:缓冲区大小,修改为64m
5.调整生产者线程数和并行度:增加并发请求的数量(max.in.flight.requests.per.connection)。
6.优化网络和硬件资源:确保网络带宽和磁盘 I/O 性能足够。
10、zk在kafka集群中有何作用
Kafka使用zk的分布式协调服务,将生产者,消费者,消息储存(broker,用于存储信息,消息读写等)结合在一起。同时借助zk,kafka能够将生产者,消费者和broker在内的所有组件在无状态的条件下建立起生产者和消费者的订阅关系,实现生产者的负载均衡,只有在zk的节点上存了数据才算被zk管理,只注册监听不算被zk管
随着 KRaft 模式(Kafka Raft)引入,Kafka 正在逐步减少对 Zookeeper 的依赖,并试图实现完全通过 Kafka 自身的协议进行协调管理
11、简述kafka集群中的Leader选举机制
Controller leader
当broker启动的时候,都会创建KafkaController对象,但是集群中只能有一个leader对外提供服务,这些每个节点上的KafkaController会在指定的zookeeper路径下创建临时节点,只有第一个成功创建的节点的KafkaController才可以成为leader责管理集群broker 的上下线,所有 topic 的分区副本分配和 Leader 选举等工作,其余的都是follower。当leader故障后,所有的follower会收到通知,再次竞争在该路径下创建节点从而选举新的leader
1.controller谁先注册,谁是leader.谁说了算
2.选举出来的Controller监听所有的brokers节点变化
3.Controller决定 Partition leader的选举(选举规则:在isr中存活为前提,按照AR中排在前面的优先。例如ar[1,0.2l,isr「1,0,2,那么leader就会按照1,0,2的顺序轮询)
4.Controller将节点信息上传到ZK
5.其他contorller从zk同步相关信息
6.假设Broker1中Leader挂了
7.Controller监听到节点变化
8.获取ISR
9.选举新的Leader(在isr中存活为前提,按照AR中排在前面的优先)
更新Leader及ISR
如图:partition leader 2挂了 后边节点 isr中存活为前提,按照AR中排在前面的优先 3接任 成为新leader
12、kafka是如何处理数据乱序问题的。
出现乱序的原因:
1)生产者在发送3请求的时候,发生异常,发生异常需要重新发送,所以排在了后面,在进行落盘的时候,先落盘1,2 ,落盘3的时候发现是4,需要等,等到3出现为止,然后将 3,4 ,5排序,排序后再进行落盘。
顺序错乱了,会自动排序(开启幂等性)。有点类似于按大家成绩排名来选座位,第三名窜稀上厕所,必须等第三名回来选完再说
1.幂等性生产者:
kafka在1.x版本之前保证数据单分区有序,条件如下:
max.in.flight.requests.per.connection=1不需要考虑是否开启幂等性)。因此在一个分区内是不需要考虑数据会不会乱序的问题的
kafka在1.x及以后版本保证数据单分区有序,条件如下:
开启幂等性 max.in.flight.requests.per.connection需要设置小于等于5。
未开启幂等性 max.in.flight.requests.per.connection需要设置为1。
2.事务:
Kafka 支持事务机制,生产者可以通过事务确保一组消息的原子性提交,从而避免乱序问题。在事务中,消息的发送和偏移量的提交是原子操作,确保消息顺序的一致性。
分区
分区机制
- kafka 主题(Topic)可以分为多个分区。每个分区在物理上是独立的日志文件,消息在分区中按顺序存储。
- 生产者发送消息时,可以通过分区键(Partition Key)将消息路由到特定的分区。同一个分区键的消息会发送到同一个分区。
区内的顺序:
- 在同一个分区中,消息是严格按顺序存储的。每条消息都有一个唯一的偏移量,偏移量是按顺序递增的。
- 因此,同一个分区的消息总是按照发送顺序被消费。
- 消息偏移量(Offset)
偏移量机制:
- 每个分区中的每条消息都有一个唯一的偏移量,偏移量是分区内消息的位置标识。
- 偏移量提交:
-
- 消费者可以在处理完消息后提交偏移量,表示已经成功消费了这些消息。偏移量通常按顺序提交,确保消息按顺序处理。
分区数量和消费者组
- 分区数量:
-
- 分区数量影响并行度和顺序性。增加分区数量可以提高并行度,但在某些情况下可能导致不同分区的消息顺序不一致。
- 因此,在高顺序性要求的场景下,通常需要合理控制分区数量。
- 消费者组:
-
- 同一个消费者组中的消费者负责消费不同的分区,确保每个分区内的消息顺序。
- 不同分区的消息顺序可能不同,因此消费者组的设计需要考虑分区数量和消息顺序的要求
13、kafka中节点如何服役和退役
1.开启一台新的服务器
在第一台服务器修改hosts,把新的虚拟机的ip和主机名加进去
xsync 同步到另外三台 这台新的也把其他三台的hosts加进去
2.新增的服务器config/server.properties 里的broker.id=3
3.删除 bigdata04 中 kafka 下的 datas 和 logs。 rm -rf datas/* logs/*
4. 启动kafka集群(只能启动三台)
5.单独启动 bigdata04 中的 kafka。
bin/kafka-server-start.sh -daemon ./config/server.properties
6.创建一个要均衡的主题
查看kafka集群first主题的详情:
创建一个文件:vi topics-to-move.json
写上如下代码,如果多个topic 可以使用,分隔
{
"topics": [
{"topic": "third"}
],
"version": 1
}
bin/kafka-reassign-partitions.sh --bootstrap-server bigdata01:9092
--topics-to-move-json-file topics-to-move.json --broker-list "0,1,2,3" --generate
把上边的文件拷贝一份 创建副本存储计划(所有副本存储在 broker0、broker1、broker2、broker3 中)。
vi increase-replication-factor.json
执行:
bin/kafka-reassign-partitions.sh --bootstrap-server bigdata01:9092 --reassignment-json-file increase-replication-factor.json --execute
验证副本存储计划。
bin/kafka-reassign-partitions.sh --bootstrap-server bigdata01:9092 --reassignment-json-file increase-replication-factor.json --verify
退役旧节点
和以上操作基本一致 执行计划的节点数 要把想要退役的节点剔除
14、Kafka中Leader挂了,Follower挂了,然后再启动,数据如何同步?
Leader选举:当Leader挂掉时,Kafka会通过Zookeeper和控制器选举新的Leader,确保集群继续运行。
ISR(In-Sync Replicas):Kafka通过ISR列表确保只有同步的副本才会被选为Leader或提供服务。副本同步滞后太多时会被临时移除ISR列表。
数据恢复与同步:恢复的Leader或Follower会从当前的Leader节点同步数据,直到其数据一致。
副本数量:通过合理配置副本数量(通常为3个),可以提高集群的容错能力,减少数据丢失的风险。
15、kafka中初始化的时候Leader选举有一定的规律,如何打破这个规律呢?
修改 auto.leader.rebalance.enable 和 preferred.leader.election.enable 配置,控制是否自动重新平衡 Leader。
手动触发 Leader 选举,使用 kafka-leader-election.sh 工具。
调整分区副本分配策略,通过自定义分区器改变副本的分配方式。
改变 Broker 优先级,调整集群中不同 Broker 的优先级。
使用自定义的控制器逻辑,但这种方式较为复杂。