Kafka Broker
一:Broker工作流程
1:Zookeeper存储的Kafka信息
高版本的Kafka已经可以不使用zookeeper
zookeeper存储了Kafka各种各样的相关信息:
- 记录了有哪些Kafka服务器:
/kafka/brokers/ids - 记录了这些服务器中谁是Leader:
/kafka/borkers/topics/first/partiontions/0/state - 记录了哪些服务可用:
/kafka/borkers/topics/first/partiontions/0/state - 记录了协调者contorller[谁去辅助选举Leader]:
/kafka/controller
2:Kafka Broker总体工作流程

- broker在启动之后在zk中注册
- controller的确定:谁先在zookeeper中注册,谁作为主controller,谁说了算
- 由选举出来的Controller监听brokers节点的变化
- controller决定了Leader选举【选举的规则是:在isr中存活为前提,按照AR(All Reflica)中排在前面的优先】
- 将节点信息上传到ZK
- 其他controller从zk同步相关的信息
- 假设broker1中Leader挂了,Controller就会监听到节点的变化,然后获取ISR,选举新的Leader,最后更新Leader & ISR

拟Kafka上下线,Zookeeper中数据变化
# 查看/kafka/brokers/ids路径上的节点
ls /kafka/brokers/ids
[0, 1, 2]
# 查看/kafka/controller路径上的数据
{"version":1,"brokerid":0,"timestamp":"1637292471777"}
# 查看/kafka/brokers/topics/first/partitions/0/state路径上的数据
get /kafka/brokers/topics/first/partitions/0/state
{"controller_epoch":24,"leader":0,"version":1,"leader_epoch":18,"isr":[0,1,2]}
下线测试
# 停止hadoop104上的kafka
[hadoop104 kafka]$ bin/kafka-server-stop.sh
# 再次查看/kafka/brokers/ids路径上的节点
ls /kafka/brokers/ids
[0, 1]
# 再次查看/kafka/controller路径上的数据
get /kafka/controller
{"version":1,"brokerid":0,"timestamp":"1637292471777"}
# 再次查看/kafka/brokers/topics/first/partitions/0/state路径上的数据
get /kafka/brokers/topics/first/partitions/0/state
{"controller_epoch":24,"leader":0,"version":1,"leader_epoch":18,"isr":[0,1]}
3:Broker重要参数
| 参数名称 | 描述 |
|---|---|
| replica.lag.time.max.ms | ISR中,如果Follower长时间未向Leader发送通信请求或同步数据,则该Follower将被踢出ISR。 该时间阈值,默认30s。 |
| auto.leader.rebalance.enable | 默认是true。 自动Leader Partition 平衡。 |
| leader.imbalance.per.broker.percentage | 默认是10%。每个broker允许的不平衡的leader的比率。 如果每个broker超过了这个值,控制器会触发leader的平衡。 |
| leader.imbalance.check.interval.seconds | 默认值300秒。检查leader负载是否平衡的间隔时间。 |
| log.segment.bytes | Kafka中log日志是分成一块块存储的,此配置是指log日志划分 成块的大小,默认值1G。 |
| log.index.interval.bytes | 默认4kb,kafka里面每当写入了4kb大小的日志(.log),然后就往index文件里面记录一个索引。 |
| log.retention.hours | Kafka中数据保存的时间,默认7天。 |
| log.retention.minutes | Kafka中数据保存的时间,分钟级别,默认关闭。 |
| log.retention.ms | Kafka中数据保存的时间,毫秒级别,默认关闭。 |
| log.retention.check.interval.ms | 检查数据是否保存超时的间隔,默认是5分钟。 |
| log.retention.bytes | 默认等于-1,表示无穷大。超过设置的所有日志总大小,删除最早的segment。 |
| log.cleanup.policy | 默认是delete,表示所有数据启用删除策略; 如果设置值为compact,表示所有数据启用压缩策略。 |
| num.io.threads | 默认是8。负责写磁盘的线程数。整个参数值要占总核数的50%。 |
| num.replica.fetchers | 副本拉取线程数,这个参数占总核数的50%的1/3 |
| num.network.threads | 默认是3。数据传输线程数,这个参数占总核数的50%的2/3 。 |
| log.flush.interval.messages | 强制页缓存刷写到磁盘的条数,默认是long的最大值,9223372036854775807。 一般不建议修改,交给系统自己管理。 |
| log.flush.interval.ms | 每隔多久,刷数据到磁盘,默认是null。一般不建议修改,交给系统自己管理。 |
二:生产经验
1:新节点的服役
新节点的准备
关闭hadoop4,并且右键执行克隆操作,开启hadoop5,并修改ip地址
vim /etc/sysconfig/network-scripts/ifcfg-ens33
DEVICE=ens33
TYPE=Ethernet
ONBOOT=yes
BOOTPROTO=static
NAME="ens33"
IPADDR=192.168.10.105 # <-------- 注意修改这行
PREFIX=24
GATEWAY=192.168.10.2
DNS1=192.168.10.2
在hadoop105上,修改主机名称为hadoop105
vim /etc/hostname
hadoop105
重新启动hadoop104、hadoop105。 -> 修改haodoop105中kafka的broker.id为3。 -> 删除hadoop105中kafka下的datas和logs。
rm -rf datas/* logs/*
启动hadoop102、hadoop103、hadoop104上的kafka集群
zk.sh start
kf.sh start
单独启动hadoop105中的kafka
bin/kafka-server-start.sh -daemon ./config/server.properties
执行负载均衡操作
创建一个要均衡的主题
vim topics-to-move.json
{
"topics": [
{"topic": "first"}
],
"version": 1
}
生成一个负载均衡的计划
# 生成负载均衡的计划
[hadoop102 kafka]$ bin/kafka-reassign-partitions.sh --bootstrap-server hadoop102:9092
--topics-to-move-json-file topics-to-move.json
--broker-list "0,1,2,3"
--generate
Current partition replica assignment
{"version":1,"partitions":[{"topic":"first","partition":0,"replicas":[0,2,1],"log_dirs":["any","any","any"]},{"topic":"first","partition":1,"replicas":[2,1,0],"log_dirs":["any","any","any"]},{"topic":"first","partition":2,"replicas":[1,0,2],"log_dirs":["any","any","any"]}]}
Proposed partition reassignment configuration
{"version":1,"partitions":[{"topic":"first","partition":0,"replicas":[2,3,0],"log_dirs":["any","any","any"]},{"topic":"first","partition":1,"replicas":[3,0,1],"log_dirs":["any","any","any"]},{"topic":"first","partition":2,"replicas":[0,1,2],"log_dirs":["any","any","any"]}]}
创建副本存储计划(所有副本存储在broker0、broker1、broker2、broker3中)
vim increase-replication-factor.json
# 输入下面的内容
{
"version":1,
"partitions":[
{
"topic":"first",
"partition":0,
"replicas":[2,3,0],
"log_dirs":["any","any","any"]
},
{
"topic":"first",
"partition":1,
"replicas":[3,0,1],
"log_dirs":["any","any","any"]
},
{
"topic":"first",
"partition":2,
"replicas":[0,1,2],
"log_dirs":["any","any","any"]
}
]
}
执行副本存储计划
bin/kafka-reassign-partitions.sh --bootstrap-server hadoop102:9092
--reassignment-json-file increase-replication-factor.json
--execute
验证副本存储计划
bin/kafka-reassign-partitions.sh --bootstrap-server hadoop102:9092
--reassignment-json-file increase-replication-factor.json
--verify
2:旧节点的退役
执行负载均衡操作
先按照退役一台节点,生成执行计划,然后按照服役时操作流程执行负载均衡。
创建一个要均衡的主题
[hadoop102 kafka]$ vim topics-to-move.json
{
"topics": [
{"topic": "first"}
],
"version": 1
}
创建执行计划
bin/kafka-reassign-partitions.sh --bootstrap-server hadoop102:9092
--topics-to-move-json-file topics-to-move.json
--broker-list "0,1,2"
--generate
Current partition replica assignment
{"version":1,"partitions":[{"topic":"first","partition":0,"replicas":[2,0,1],"log_dirs":["any","any","any"]},{"topic":"first","partition":1,"replicas":[3,1,2],"log_dirs":["any","any","any"]},{"topic":"first","partition":2,"replicas":[0,2,3],"log_dirs":["any","any","any"]}]}
Proposed partition reassignment configuration
{"version":1,"partitions":[{"topic":"first","partition":0,"replicas":[2,0,1],"log_dirs":["any","any","any"]},{"topic":"first","partition":1,"replicas":[0,1,2],"log_dirs":["any","any","any"]},{"topic":"first","partition":2,"replicas":[1,2,0],"log_dirs":["any","any","any"]}]}
创建副本存储计划(所有副本存储在broker0、broker1、broker2中)
vim increase-replication-factor.json
# 输入下面的内容
{
"version":1,
"partitions":[
{
"topic":"first",
"partition":0,
"replicas":[2,0,1],
"log_dirs":["any","any","any"]
},
{
"topic":"first",
"partition":1,
"replicas":[0,1,2],
"log_dirs":["any","any","any"]
},
{
"topic":"first",
"partition":2,
"replicas":[1,2,0],
"log_dirs":["any","any","any"]
}
]
}
执行副本存储计划
bin/kafka-reassign-partitions.sh --bootstrap-server hadoop102:9092
--reassignment-json-file increase-replication-factor.json
--execute
验证副本存储计划
bin/kafka-reassign-partitions.sh --bootstrap-server hadoop102:9092
--reassignment-json-file increase-replication-factor.json
--verify
Status of partition reassignment:
Reassignment of partition first-0 is complete.
Reassignment of partition first-1 is complete.
Reassignment of partition first-2 is complete.
Clearing broker-level throttles on brokers 0,1,2,3
Clearing topic-level throttles on topic first
执行停止命令
bin/kafka-server-stop.sh
三:Kafka 分区副本(重点,面试点)
1:主题,分区和副本
一个非常大的topic可以分布到多个broker(即服务器)上
一个topic可以分为多个partition,每个partition是一个有序的队列。
一个topic的每个分区partition都有若干个副本replica,一个Leader和若干个Follower。

- Leader:每个分区多个副本的“主”,生产者发送数据的对象,以及消费者消费数据的对象都是Leader
- Follower:每个分区多个副本中的“从”,实时从Leader中同步数据,保持和Leader数据的同步。Leader发生故障时,某个Follower会成为新的Leader。
2:副本基本信息
副本的作用:提高数据的可靠性(冗余 -> 提高可靠性,常见架构手段)
Kafka默认副本1个,生产环境一般配置为2个,保证数据可靠性;太多副本会增加磁盘存储空间,增加网络上数据传输,降低效率
Kafka中副本分为:Leader和Follower。
Kafka生产者只会把数据发往Leader,然后Follower找Leader进行同步数据
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副本同步时,延迟过多的副本。
还有两个重要的offset点名词需要记住:
- LEO(Log End Offset)每一个副本最后的一个offset,LEO = 最新的Offset + 1
- HW (High Watermark) 所有副本的最小的LEO

3:Leader选举流程(面)
Kafka集群中有一个broker的Controller会被选举为Controller Leader
Controller Leader负责管理集群broker的上下线,所有topic的分区副本分配和Leader选举等工作。
Controller的信息同步工作是依赖于Zookeeper的。【前面已经说过了,详见Kafka Broker总体工作流程】

创建一个新的topic,4个分区,4个副本
bin/kafka-topics.sh --bootstrap-server hadoop102:9092
--create --topic test # 创建一个topic叫做test
--partitions 4 # 4个分区
--replication-factor 4 # 4个副本
Created topic test.
查看Leader分布情况
bin/kafka-topics.sh --bootstrap-server hadoop102:9092
--describe
--topic test
Topic: test TopicId: awpgX_7WR-OX3Vl6HE8sVg PartitionCount: 4 ReplicationFactor: 4 Configs: segment.bytes=1073741824
Topic: test Partition: 0 Leader: 3 Replicas: 3,0,2,1 Isr: 3,0,2,1
Topic: test Partition: 1 Leader: 1 Replicas: 1,2,3,0 Isr: 1,2,3,0
Topic: test Partition: 2 Leader: 0 Replicas: 0,3,1,2 Isr: 0,3,1,2
Topic: test Partition: 3 Leader: 2 Replicas: 2,1,0,3 Isr: 2,1,0,3
停止掉hadoop105的kafka进程,并查看Leader分区情况
[hadoop105 kafka]$ bin/kafka-server-stop.sh
[hadoop102 kafka]$ bin/kafka-topics.sh --bootstrap-server hadoop102:9092
--describe
--topic test
Topic: test TopicId: awpgX_7WR-OX3Vl6HE8sVg PartitionCount: 4 ReplicationFactor: 4 Configs: segment.bytes=1073741824
Topic: test Partition: 0 Leader: 0 Replicas: 3,0,2,1 Isr: 0,2,1
Topic: test Partition: 1 Leader: 1 Replicas: 1,2,3,0 Isr: 1,2,0
Topic: test Partition: 2 Leader: 0 Replicas: 0,3,1,2 Isr: 0,1,2
Topic: test Partition: 3 Leader: 2 Replicas: 2,1,0,3 Isr: 2,1,0
停止掉hadoop104的kafka进程,并查看Leader分区情况
[hadoop104 kafka]$ bin/kafka-server-stop.sh
[hadoop102 kafka]$ bin/kafka-topics.sh --bootstrap-server hadoop102:9092
--describe
--topic test
Topic: test TopicId: awpgX_7WR-OX3Vl6HE8sVg PartitionCount: 4 ReplicationFactor: 4 Configs: segment.bytes=1073741824
Topic: test Partition: 0 Leader: 0 Replicas: 3,0,2,1 Isr: 0,1
Topic: test Partition: 1 Leader: 1 Replicas: 1,2,3,0 Isr: 1,0
Topic: test Partition: 2 Leader: 0 Replicas: 0,3,1,2 Isr: 0,1
Topic: test Partition: 3 Leader: 1 Replicas: 2,1,0,3 Isr: 1,0
启动hadoop105的kafka进程,并查看Leader分区情况
[hadoop105 kafka]$ bin/kafka-server-start.sh -daemon config/server.properties
[hadoop102 kafka]$ bin/kafka-topics.sh --bootstrap-server hadoop102:9092
--describe
--topic test
Topic: test TopicId: awpgX_7WR-OX3Vl6HE8sVg PartitionCount: 4 ReplicationFactor: 4 Configs: segment.bytes=1073741824
Topic: test Partition: 0 Leader: 0 Replicas: 3,0,2,1 Isr: 0,1,3
Topic: test Partition: 1 Leader: 1 Replicas: 1,2,3,0 Isr: 1,0,3
Topic: test Partition: 2 Leader: 0 Replicas: 0,3,1,2 Isr: 0,1,3
Topic: test Partition: 3 Leader: 1 Replicas: 2,1,0,3 Isr: 1,0,3
4:故障处理细节(重点)
4.1:Follower故障
- 被临时的踢出ISR,这个期间,其他的Leader & Follower正常接收数据
- 该Follower恢复之后,会读取自己上一次记录的HW【高水位】,然后将Log中高于HW的全部截取掉,从HW开始同步
- 等LEO >= 这个分区的HW,也就表名了Follower追上了Leader,此时就可以将这个Follwer重新加入回到ISR

4.2:Leader故障
- 从ISR中选出新的Leader
- 为了保证数据的一致性,其余的没有竞选成功的Follower会选择将各自的高于HW的部分截掉,然后从新的Leader同步数据
- 这种方式只能保证数据一致性,不能保证数据不丢失或者不重复

分区副本的分配
如果kafka服务器只有4个节点,那么设置kafka的分区数大于服务器台数,在kafka底层如何分配存储副本呢
创建16分区,3个副本:
(1)创建一个新的topic,名称为second
[hadoop102 kafka]$ bin/kafka-topics.sh --bootstrap-server hadoop102:9092
--create --partitions 16
--replication-factor 3
--topic second
(2)查看分区和副本情况
bin/kafka-topics.sh --bootstrap-server hadoop102:9092
--describe
--topic second
Topic: second4 Partition: 0 Leader: 0 Replicas: 0,1,2 Isr: 0,1,2
Topic: second4 Partition: 1 Leader: 1 Replicas: 1,2,3 Isr: 1,2,3
Topic: second4 Partition: 2 Leader: 2 Replicas: 2,3,0 Isr: 2,3,0
Topic: second4 Partition: 3 Leader: 3 Replicas: 3,0,1 Isr: 3,0,1
Topic: second4 Partition: 4 Leader: 0 Replicas: 0,2,3 Isr: 0,2,3
Topic: second4 Partition: 5 Leader: 1 Replicas: 1,3,0 Isr: 1,3,0
Topic: second4 Partition: 6 Leader: 2 Replicas: 2,0,1 Isr: 2,0,1
Topic: second4 Partition: 7 Leader: 3 Replicas: 3,1,2 Isr: 3,1,2
Topic: second4 Partition: 8 Leader: 0 Replicas: 0,3,1 Isr: 0,3,1
Topic: second4 Partition: 9 Leader: 1 Replicas: 1,0,2 Isr: 1,0,2
Topic: second4 Partition: 10 Leader: 2 Replicas: 2,1,3 Isr: 2,1,3
Topic: second4 Partition: 11 Leader: 3 Replicas: 3,2,0 Isr: 3,2,0
Topic: second4 Partition: 12 Leader: 0 Replicas: 0,1,2 Isr: 0,1,2
Topic: second4 Partition: 13 Leader: 1 Replicas: 1,2,3 Isr: 1,2,3
Topic: second4 Partition: 14 Leader: 2 Replicas: 2,3,0 Isr: 2,3,0
Topic: second4 Partition: 15 Leader: 3 Replicas: 3,0,1 Isr: 3,0,1

5:副本生产经验
5.1:手动调整分区副本存储

手动调整分区副本存储的步骤如下:
- 创建一个新的topic,名称为three
bin/kafka-topics.sh --bootstrap-server hadoop102:9092
--create
--partitions 4
--replication-factor 2
--topic three
- 查看分区副本存储情况
bin/kafka-topics.sh --bootstrap-server hadoop102:9092
--describe
--topic three
- 创建副本存储计划(所有副本都指定存储在broker0、broker1中)
vim increase-replication-factor.json
{
"version":1,
"partitions":[
{"topic":"three","partition":0,"replicas":[0,1]},
{"topic":"three","partition":1,"replicas":[0,1]},
{"topic":"three","partition":2,"replicas":[1,0]},
{"topic":"three","partition":3,"replicas":[1,0]}
]
}
- 执行副本存储计划
bin/kafka-reassign-partitions.sh --bootstrap-server hadoop102:9092
--reassignment-json-file increase-replication-factor.json # 指定存储计划文件
--execute # 执行存储计划
- 验证副本存储计划
bin/kafka-reassign-partitions.sh --bootstrap-server hadoop102:9092
--reassignment-json-file increase-replication-factor.json
--verify # 验证存储计划
- 查看分区副本存储情况
bin/kafka-topics.sh --bootstrap-server hadoop102:9092
--describe
--topic three
5.2:Leader Partition负载平衡

| 参数名称 | 描述 |
|---|---|
| auto.leader.rebalance.enable | 默认是true。 自动Leader Partition 平衡。生产环境中,leader重选举的代价比较大,可能会带来性能影响,建议设置为false关闭。 |
| leader.imbalance.per.broker.percentage | 默认是10%。每个broker允许的不平衡的leader的比率。如果每个broker超过了这个值,控制器会触发leader的平衡。 |
| leader.imbalance.check.interval.seconds | 默认值300秒。检查leader负载是否平衡的间隔时间。 |
5.3:增加副本因子
在生产环境当中,由于某个主题的重要等级需要提升,我们考虑增加副本。
副本数的增加需要先制定计划,然后根据计划执行
vim increase-replication-factor.json
{
"version":1,
"partitions":[
{"topic":"four","partition":0,"replicas":[0,1,2]},
{"topic":"four","partition":1,"replicas":[0,1,2]},
{"topic":"four","partition":2,"replicas":[0,1,2]}
]
}
四:文件存储
1:文件存储机制
1.1:Topic数据的存储机制

1.2:index文件和log文件详解

说明:日志存储参数配置
| 参数 | 描述 |
|---|---|
| log.segment.bytes | Kafka中log日志是分成一块块存储的,此配置是指log日志划分 成块的大小,默认值1G。 |
| log.index.interval.bytes | 默认4kb,kafka里面每当写入了4kb大小的日志(.log),然后就往index文件里面记录一个索引。 稀疏索引。 |
2:文件清理策略
Kafka中默认的日志保存时间为7天,可以通过调整如下参数修改保存时间。
log.retention.hours,最低优先级小时,默认7天。log.retention.minutes,分钟。log.retention.ms,最高优先级毫秒。log.retention.check.interval.ms,负责设置检查周期,默认5分钟。
那么日志一旦超过了设置的时间,怎么处理呢?
Kafka中提供的日志清理策略有delete和compact两种。
delete日志删除:将过期数据删除log.cleanup.policy = delete所有数据启用删除策略- 基于时间:默认打开。以segment中所有记录中的最大时间戳作为该文件时间戳。
- 基于大小:默认关闭。超过设置的所有日志总大小,删除最早的segment ->
log.retention.bytes,默认等于-1,表示无穷大。
compact日志压缩

五:高效读写数据
- Kafka本身是分布式集群,可以采用分区技术,并行度高
- 读数据采用稀疏索引,可以快速定位要消费的数据
- 顺序写磁盘
Kafka的producer生产数据,要写入到log文件中,写的过程是一直追加到文件末端,为顺序写。
官网有数据表明,同样的磁盘,顺序写能到600M/s,而随机写只有100K/s。
这与磁盘的机械机构有关,顺序写之所以快,是因为其省去了大量磁头寻址的时间。

页缓存 + 零拷贝技术

799

被折叠的 条评论
为什么被折叠?



