资料全部来源于尚硅谷,如果有侵权请联系删除
1. 基础
- Kafka是一个分布式的基于发布/订阅模式的消息队列(Message
Queue),主要应用于大数据实时处理领域。 - 传统消息队列的应用场景:缓存/消峰、解耦(超市)和异步通信(先处理核心)。
- 消息队列的两种模式
1)点对点模式
• 消费者主动拉取数据,消息收到后清除消息
2)发布/订阅模式
• 可以有多个topic主题
• 消费者消费数据之后,不删除数据 - Kafka 基础架构
2. 快速入门
Kafka 命令行操作
查看当前服务器中的所有 topic
bin/kafka-topics.sh --bootstrap-server hadoop101:9092 --list
创建 first topic
bin/kafka-topics.sh --bootstrap-server hadoop102:9092 --create --partitions 1 --replication-factor 3 --topic first
查看详情
bin/kafka-topics.sh --bootstrap-server hadoop102:9092 --describe --topic first
修改分区数(注意:分区数只能增加,不能减少)
bin/kafka-topics.sh --bootstrap-server hadoop102:9092 --alter --topic first --partitions 3
生产者命令行操作
bin/kafka-console-producer.sh --bootstrap-server hadoop102:9092 --topic first
3. Kafka 生产者
生产者消息发送流程*****************
原理
每个缓存队列默认32m,每个分区一个队列,数据大小默认16k。
异步发送
同步发 送
send().get()
生产者分区
Kafka 分区好处
(1)便于合理使用存储资源,每个Partition在一个Broker上存储,合理控制分区的任务,可以实现负载均衡的效果。
(2)提高并行度,生产者可以以分区为单位发送数据;消费者可以以分区为单位进行消费数据。
生产者发送消息的分区策略
1)默认的分区器 DefaultPartitioner *****
指定分区时,按指定的;没指定分区但有key值,按key的hash值与topic分区数取余;既没分区也没key,采用黏性分区器(sticky partition) 随机选择一个分区,并且尽可能使用该分区,直到该分区的batch从满在随机另一个分区(和上次不同分区)
自定义分区器
重写Partitioner
生产经验——生产者如何提高吞吐量*******
- // batch.size:批次大小,默认 16K
properties.put(ProducerConfig.BATCH_SIZE_CONFIG, 16384); - // linger.ms:等待时间,默认 0
太高会延迟大
properties.put(ProducerConfig.LINGER_MS_CONFIG, 1); - // RecordAccumulator:缓冲区大小,默认 32M:buffer.memory
properties.put(ProducerConfig.BUFFER_MEMORY_CONFIG, - // compression.type:压缩,默认 none,可配置值 gzip、snappy、lz4 和 zstd
properties.put(ProducerConfig.COMPRESSION_TYPE_CONFIG,“snappy”);
生产经验——数据可靠性
数据完全可靠条件 = ACK级别设置为-1 + 分区副本大于等于2 + ISR里应答的最小副本数量大于等于2
总结:
acks=0,生产者发送过来数据就不管了,可靠性差,效率高;数据丢失。
acks=1,生产者发送过来数据Leader应答,可靠性中等,效率中等;传输普通日志。
acks=-1,生产者发送过来数据Leader和ISR队列里面所有Follwer应答,可靠性高,效率低;
在生产环境中,acks=0很少使用;acks=1,一般用于传输普通日志,允许丢个别数据;acks=-1,一般用于传输和钱相关的数据,对可靠性要求比较高的场景。
生产经验——数据去重
精确一次(Exactly Once):对于一些非常重要的信息,比如和钱相关的数据,要求数据既不能重复也不丢失。幂等性和事务
幂等性************
幂等性就是指Producer不论向Broker发送多少次重复数据,Broker端都只会持久化一条,保证了不重复
精确一次(Exactly Once) = 幂等性 + 至少一次( ack=-1 + 分区副本数>=2 + ISR最小副本数量>=2) 。
d:具有**<PID, Partition, SeqNumber>**相同主键的消息提交时,Broker只会持久化一条。其中PID是Kafka每次重启都会分配一个新的;Partition 表示分区号;Sequence Number是单调自增的。所以幂等性只能保证的是在单分区单会话内不重复。
事务原理
数据乱序*************************
保证5个request是有序的,例如3没有发过来,4 5就会在缓存中等待,1 2 存入,直到3到了,然后一次存储。
Kafka Broker
Kafka Broker工作流程**********
远程Kafka端口号:2181
在zookeeper的服务端存储的Kafka相关信息:
1)/kafka/brokers/ids [0,1,2] 记录有哪些服务器
2)/kafka/brokers/topics/first/partitions/0/state
{“leader”:1 ,“isr”:[1,0,2] } 记录谁是Leader,有哪些服务器可用
Zookeeper中存储的Kafka 信息
{“version”:1,“brokerid”:0,“timestamp”:“1635907476”}
3)/kafka/controller
{“brokerid”:0}
辅助选举Leader
节点服役和退役
服役新节点后需要生成负载均衡计划,创建副本存储计划,执行副本存储计划,验证副本存储计划。
退役旧节点:创建执行计划,创建副本存储计划,执行副本存储计划,验证副本存储计划,执行停止命令
Kafka副本
生产环境一般配置两个副本,默认是1个。
Kafka中数据只会发给leader,然后follower找leader同步数据;Hadoop中是每个副本是等价的。
Kafka 分区中的所有副本统称为 AR(Assigned Repllicas)。
AR = ISR + OSR
ISR,表示和 Leader 保持同步的 Follower 集合。如果 Follower 长时间未向 Leader 发送通信请求或同步数据,则该 Follower 将被踢出 ISR。该时间阈值由 replica.lag.time.max.ms参数设定,默认 30s。Leader 发生故障之后,就会从 ISR 中选举新的 Leader。
OSR,表示 Follower 与 Leader 副本同步时,延迟过多的副本。
Leader 选举流程
选举新的leader,在isr中存活为前提,按照AR中排在最前面的优先。
leader和follow故障细节
消费者能看到的数据是最高水位线的数据。
分区副本分配
尽可能循环节点均匀分配,负载均衡
手动分配副本
创建存储计划
vim increase-replication-factor.json
执行存储计划
bin/kafka-reassign-partitions.sh --bootstrap-server hadoop102:9092 --reassignment-json-file increase-replication-factor.json --execute
Leader Partition 负载平衡
Kafka本身会自动把Leader Partition均匀分散在各个机器上,但是如果某些broker宕机,会导致Leader Partition过于集中在其他少部分几台broker上,这会导致少数几台broker的读写请求压力过高,其他宕机的broker重启之后都是follower partition,读写请求很低,造成集群负载不均衡。
注意:切记每个分区都有一个leader
参数设置:
auto.leader.rebalance.enable,默认是true。自动Leader Partition 平衡
leader.imbalance.per.broker.percentage,默认是10%。每个broker允许的不平衡的leader的比率。如果每个broker超过了这个值,控制器会触发leader的平衡。
leader.imbalance.check.interval.seconds,默认值300秒。检查leader负载是否平衡的间隔时间。
文件存储
文件存储机制
1)Topic 数据的存储机制
- log.segment.bytes Kafka 中 log 日志是分成一块块存储的,此配置是指 log 日志划分
成块的大小,默认值 1G。 - log.index.interval.bytes index是稀疏索引,往log写入4kb数据,往index文件写入一条索引
文件清理策略
Kafka 中默认的日志保存时间为 7 天
1)delete 日志删除:将过期数据删除
(1)基于时间:默认打开。以 segment 中所有记录中的最大时间戳作为该文件时间戳。
(2)基于大小:默认关闭。超过设置的所有日志总大小,删除最早的 segment。
2)compact 日志压缩
log.cleanup.policy = compact 所有数据启用压缩策略
compact日志压缩:对于相同key的不同value值,只保留最后一个版本。
压缩后的offset可能是不连续的,这种策略只适合特殊场景,比如消息的key是用户ID,value是用户的资料
高效读写数据 *重要
1)Kafka 本身是分布式集群,可以采用分区技术,并行度高
2)读数据采用稀疏索引,可以快速定位要消费的数据
3)顺序写磁盘,写的过程是一直追加到文件末端
4)页缓存 + 零拷贝技术
5. Kafka 消费者
由于消费者接收速率各不相同,Kafka采用消费者主动从broker中拉取数据,不足之处在于如果Kafka没有数据就会陷入循环,返回空数据。
消费者工作流程
消费者组原理
Consumer Group(CG):消费者组,由多个consumer组成。形成一个消费者组的条件,是所有消费者的groupid相同。
• 消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一个组内消费者消费。
• 消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。
• 如果向消费组中添加更多的消费者,超过主题分区数量,则有一部分消费者就会闲置,不会接收任何消息。
消费者初始化流程
消费者 API
在消费者 API 代码中必须配置消费者组 id。命令行启动消费者不填写消费者组id 会被自动填写随机的消费者组 id。
生产经验——分区的分配以及再平衡
Kafka有四种主流的分区分配策略: Range、RoundRobin、Sticky、CooperativeSticky。
可以通过配置参数partition.assignment.strategy,修改分区的分配策略。默认策略是Range + CooperativeSticky。Kafka可以同时使用多个分区分配策略。
Range
Range是对每个topic而言,先对一个topic里面的分区按序号排序,并对消费者按字母顺序排序,partition数 / consumer数 决定每个消费者应该几个分区,除不尽就前面几个消费者多消费一个分区。
注意:如果是多个topic,排在前面的消费者可能每个topic都会多消费几个分区,导致数据倾斜
RoundRobin
RoundRobin 针对集群中所有Topic而言。
RoundRobin 轮询分区策略,是把所有的 partition 和所有的consumer 都列出来,然后按照 hashcode 进行排序,最后通过轮询算法来分配 partition 给到各个消费者
Sticky
首先会尽量均衡的放置分区到消费者上面,在出现同一消费者组内消费者出现问题的时候,会尽量保持原有分配的分区不变化
CooperativeSticky
offset 位移
- consumer默认将offset保存在Kafka一个内置的topic中,该topic为__consumer_offsets_(0.9版本前存在zookeeper,0.9版本后在broker中,在zookeeper中会增加网络开销)
- _consumer_offsets 主题里面采用 key 和 value 的方式存储数据。key 是 group.id+topic+
分区号,value 就是当前 offset 的值。每隔一段时间,kafka 内部会对这个 topic 进行
compact,也就是每个 group.id+topic+分区号就保留最新数据。 - 查看该系统主题数据,在配置文件 config/consumer.properties 中添加配置exclude.internal.topics=false
- Kafka提供了自动提交offset的功能。
ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG
ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG - 手动提交offset:分别是commitSync(同步提交)和commitAsync(异步提交)。
两者的相同点是,都会将本次提交的一批数据最高的偏移量提交;不同点是,同步提交阻塞当前线程,一直到提交成功,并且会自动失败重试(由不可控因素导致,也会出现提交失败);而异步提交则没有失败重试机制,故有可能提交失败。
• commitSync(同步提交):必须等待offset提交完毕,再去消费下一批数据。
• commitAsync(异步提交) :发送完提交offset请求后,就开始消费下一批数据了。 - 指定 Offset 消费
auto.offset.reset = earliest | latest | none
(1)earliest:自动将偏移量重置为最早的偏移量,–from-beginning。
(2)latest(默认值):自动将偏移量重置为最新偏移量。
(3)none:如果未找到消费者组的先前偏移量,则向消费者抛出异常 - 指定时间消费
- 漏消费和重复消费
重复消费:已经消费了数据,但是 offset 没提交。
漏消费:先提交 offset 后消费,有可能会造成数据的漏消费
采用事务可以实现精确一次性消费
生产经验——消费者事务
需要Kafka消费端将消费过程和提交offset过程做原子绑定。
必须做到:生产端–》集群 集群–》消费者 消费者–》集群 都是不能出现问题
生产经验——数据积压(消费者如何提高吞
- Kafka消费能力不足,则可以考虑增加Topic的分区数,并且同时提升消费组的消费者数量,消费者数 = 分区数。
- 下游的数据处理不及时:提高每批次拉取的数量。
6. Kafka-Eagle
Kafka-Eagle 框架可以监控 Kafka 集群的整体运行情况
1)登录页面查看监控数据
http://192.168.10.101:8048/
7. Kafka-Kraft 模式
- kafka-zookeeper模式架构的元数据在zookeeper中
- kraft 模式架构(实验性),不再依赖 zookeeper 集群,而是用三台 controller 节点代替 zookeeper,元数据保存在 controller 中,由 controller直接进行 Kafka 集群管理。
- 优势:
⚫ Kafka 不再依赖外部框架,而是能够独立运行;
⚫ controller 管理集群时,不再需要从 zookeeper 中先读取数据,集群性能上升;
⚫ 由于不依赖 zookeeper,集群扩展时不再受到 zookeeper 读写能力限制;
⚫ controller 不再动态选举,而是由配置文件规定。这样我们可以有针对性的加强
controller 节点的配置,而不是像以前一样对随机 controller 节点的高负载束手无策。
8. 集成 Flume
集成Flume
启动flume
bin/flume-ng agent -c conf/ -n a1 -f jobs/file _to_kafka.conf &
9. 生产调优
硬件选择
- 服务器台数= 2 * (生产者峰值生产速率 * 副本 / 100) + 1
- 磁盘: 每天总数据量* 副本 2 * 保存时间 3 天 / 0.7
- 内存:Kafka 内存组成:堆内存 + 页缓存
1)Kafka 堆内存建议每个节点:10g ~ 15g
2)页缓存:页缓存是 Linux 系统服务器的内存。我们只需要保证 1 个 segment(1g)中25%的数据在内存中就好。
每个节点页缓存大小 =(分区数 * 1g * 25%)/ 节点数。例如 10 个分区,页缓存大小=(10 * 1g * 25%)/ 3 ≈ 1g - cpu
num.io.threads = 8 负责写磁盘的线程数,整个参数值要占总核数的50%。
num.replica.fetchers = 1 副本拉取线程数,这个参数占总核数的 50%的1/3
um.network.threads = 3 数据传输线程数,这个参数占总核数的 50%2/3。 - 网络
网络带宽 = 峰值吞吐量
Kafka生产者
- 数据可靠性:至少一次(At Least Once)= ACK 级别设置为-1 + 分区副本大于等于 2 + ISR 里应答的最小副本数量大于等于 2
- 数据去重:开启幂等性,事务
- 数据有序
- 数据乱序:开启幂等性,允许最多没有ack的次数,保证在 1-5间
Kafka Broker
- Leader Partition 负载平衡:auto.leader.rebalance.enable 建议关闭
- 自动创建主题auto.create.topics.enable 设置为 true(默认值是 true),建议false
Kafka 消费者
- 核心参数配置
- 消费者再平衡
heartbeat.interval.ms Kafka 消费者和 coordinator 之间的心跳时间,默认3s。
session.timeout.ms:Kafka 消费者和 coordinator 之间连接超时时间,默认 45s。超过该值,该消费者被移除,消费者组执行再平衡。
max.poll.interval.ms 消费者处理消息的最大时长,默认是 5 分钟。超过该值,该消费者被移除,消费者组执行再平衡。 - 指定时间消费
- 消费者事务
- 消费者如何提高吞吐量
fetch.max.bytes 默认 Default: 52428800(50 m)。消费者获取服务器端一批消息最大的字节数。
max.poll.records 一次 poll 拉取数据返回消息的最大条数,默认是 500 条
Kafka总体
提升吞吐量
1)提升生产吞吐量
2)增加分区
3)消费者提高吞吐量
4)增加下游消费者处理能力
数据精准一次
1)生产者角度
acks 设置为-1 (acks=-1),幂等性(enable.idempotence = true) + 事务 。
2)broker 服务端角度
分区副本大于等于 2 (–replication-factor 2)。
ISR 里应答的最小副本数量大于等于 2 (min.insync.replicas = 2)。
3)消费者
事务 + 手动提交 offset (enable.auto.commit = false)。
消费者输出的目的地必须支持事务(MySQL、Kafka)。
合理设置分区数
根据压测调整分区
单条日志大于 1m
message.max.bytes 默认 1m,broker 端接收每个批次消息最大值。
max.request.size 默认 1m,生产者发往 broker 每个请求消息最大值。针对 topic级别设置消息体的大小。
replica.fetch.max.bytes 默认 1m,副本同步数据,每个批次消息最大值。
fetch.max.bytes 默认 Default: 52428800(50 m)。消费者获取服务器端一批消息最大的字节数。
集群压力测试
⚫ 生产者压测:kafka-producer-perf-test.sh
⚫ 消费者压测:kafka-consumer-perf-test.sh