文章目录

  • Kafka主题和分区-笔记3
  • 主题的增删改查
  • 新增主题
  • 查看主题
  • 修改主题
  • 主题端配置参数与broker端关系
  • 删除主题
  • KafkaAdminClient
  • 分区
  • 优先副本(preferred replica)的选举
  • 分区重分配
  • 复制限流
  • 修改副本因子
  • 分区数的选择
  • kafka性能测试
  • 合适的分区数


Kafka主题和分区-笔记3

主题和分区都是逻辑概念,分区可有一到多个副本,每个副本对应一个日志文件,每个日志文件对应一到多个日志分段LogSegment,每个日志分段还可以细分为索引文件,日志存储文件和快照文件

主题的增删改查

主题的增删改查一般通过kafka-topics.sh脚本来执行 在kafka的bin目录下
或使用KafkaAdminClient 通过XXXRequest请求

新增主题

若broker端配置参数auto.create.topics.enable设置为true(默认值),那么当生产者向一个未创建的主题发消息时(或当一个消费者开始从未知主题读取消息,或当任意一个客户端向未知主题发送元数据请求时),会自动创建一个分区数为broker端配置参数num.partitions(默认1),副本因子为default.replication.factor(默认值1)的主题

不建议auto.create.topics.enable置位true

kafka-topics.sh新增主题:本质是调用kafka.admin.TopicCommand

创建一个topic-test主题 分区数4 副本因子2
bin/kafka-topics.sh --zookeeper localhost:2181 --create --topic topic-test --partitions 4 --replication-factor 2
	--zookeeper:ZooKeeper连接地址
	--partitions:分区数
	--replication-factor:副本数
	--topic:主题名称
	
	--create:表示创建主题的指令类型,除此之外还有list,describe,alter,delete
	
Kafka会在log.dir或log.dirs参数所配置的目录下创建相应的主题分区
文件命名:<topic>-<partition> 这类文件对应的不是分区

创建一个主题时会在ZooKeeper的/brokers/topics/目录下创建一个同名的实节点

--replica-assignment参数:手动指定分区副本的分配方案,无需partitions和replication-factor参数 格式<分区1副本1所在brokerId:分区1副本2所在brokerId>,<分区2副本1所在brokerId:分区2副本2所在brokerId>
bin/kafka-topics.sh --zookeeper localhost:2181 --create --topic topic-test --replica-assignment 0:1,1:2,2:0

以上创建一个分区数3,副本数2的主题

--config:通过此参数设置要创建主题的相关参数,可覆盖原本的默认配置
	--config max.message.bytes=1000 主题端配置参数
--if-not-exists:创建主题时若主题存在则不做任何处理

主题,分区,副本和日志的关系:同一个分区中的多个副本必须分布在不同的broker 表现为一个broker不会出现重复地<topic>-<partition>命名文件


一对多

一对多

一对一

主题Topic

分区Partition

副本Replica

日志文件log


kafka-topics.sh脚本在创建主题时会检测是否包含._,kafka内部会将.改成下划线_,故而尽量避免主题名称含这两个符号

broker端参数broker.rack机架信息

Kafka支持指定broker的机架信息。若指定了机架信息,则在分区副本分配时会尽可能地让分区副本分配到不同的机架上
必须全部broker都有broker.rack参数或都没有 或使用disable-rack-aware参数忽略机架信息

查看主题

通过list和describe指令查看主题信息

查看主题内的内容

bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic topicName --from-beginning

list查看当前所有可用的主题

bin/kafka-topics.sh --zookeeper localhost:2181 --list 
test
test1
__consumer_offsets

describe查看分区副本的分配细节

bin/kafka-topics.sh --zookeeper localhost:2181 --describe --topic topic-test

Topic:PushNotice        PartitionCount:1        ReplicationFactor:1     Configs:
Topic: PushNotice       Partition: 0    Leader: 0       Replicas: 0     Isr: 0

PartitionCount分区数
ReplicationFactor副本数
Partition分区编号
Leader :leader分区所在brokerId
Replicas:副本所在brokerId,AR集合
Isr:分区的ISR集合,brokerId

--topics-with-overrides:找出所有包含覆盖配置的主题 --config,列出与集群不一样配置的主题
--under-replicated-partitions和--unavailable-partitions:找出有问题的分区
	--under-replicated-partitions找出所有包含失效副本的分区。包含失效副本的分区可能正在进行同步操作,也有可能同步发生异常,此时分区的ISR集合小于AR集合

修改主题

主题创建之后,仍然可以修改分区个数,配置等,通过alter指令
注意kafka只支持增加分区数而不支持减少分区数

alter

修改分区数
bin/kafka-topics.sh --zookeeper localhost:2181 --alter --topic topic-test --partitions 5

--if-exists:不存在则忽略

修改config配置
bin/kafka-topics.sh --zookeeper localhost:2181 --alter --topic topic-test --config max.message.bytes=2000

--delete-config:删除之前覆盖的配置,恢复原有的默认值
bin/kafka-topics.sh --zookeeper localhost:2181 --alter --topic topic-test --delete-config max.message.bytes

kafka-config.sh

包含修改配置alter和查看配置describe两种指令类型,与kafka-topics.sh不同,kafka-config.sh不仅可以操作主题相关的配置,还可以支持操作broker,用户和客户端3个类型的配置

主题端配置参数与broker端关系

若没有修改过主题的任何配置参数,那么就会使用broker端的对应参数作为其默认值

主题端参数

作用

broker端参数

cleanup.policy

日志压缩策略。默认delete,compact等

log.cleanup.policy

compression.type

消息的压缩类型。默认值producer,gzip等


delete.retention.ms

被标识删除的数据能够保留的时间,默认86400000,即1天

log.cleaner.delete.retention.ms

file.delete.delay.ms

清理文件可以等待的时间,默认60000,即1分钟

log.segment.delete.delay.ms

max.message.bytes

消息的最大字节数,默认1000012


message.timestamp.type

消息的时间戳类型,默认CreateTime,还有LogAppendTime

log.message.timestamp.type

message.timestame.difference.max.ms

消息中自带的时间戳和broker收到消息时的时间戳之间最大的差值,默认Long.MAX_VALUE,message.timestamp.type为CreateTime时有效


min.insync.replicas

分区ISR集合中至少要有多少个副本,默认1


retention.bytes

分区中所能保留的消息总量,默认-1,无限制

log.retention.bytes

retention.ms

使用delete的日志清理策略时消息能够保留的时间,默认604800000,即7天,若-1则无限制

log.retention.ms

segment.bytes

日志分段的最大值,默认1073741824,即1GB

log.segment.bytes

segment.ms

最长多久滚动一次日志分段,默认7天

log.roll.ms

unclean.leader.election.enable

是否可以从非ISR集合中选举leader副本,默认false,若true可能数据丢失


删除主题

delete指令:必须配置broker端参数delete.topic.enable为true才能删除 默认true

bin/kafka-topics.sh --zookeeper localhost:2181 --delete --topic topic-test

--if-exist

kafka-topics.sh脚本删除主题的行为本质上只是在ZooKeeper中的/admin/delete_topics路径下创建一个与待删除主题同名的节点,标记删除状态,然后由kafka的控制负责删除

ZooKeeper客户端删除主题:

zkCli.sh
create /admin/delete_topics/topic-test ""

手动删除:

主题的元数据存储在ZooKeeper中的/brokers/topics 和/config/topics路径下
主题的消息数据存储在log.dir配置的路径下 手动删除这3个地方

KafkaAdminClient

通过用KafkaAdminClient管理broker,配置和ACL,主题

创建主题
public CreateTopicsResult createTopics(final Collection<NewTopic> newTopics,
                                           final CreateTopicsOptions options)
删除主题
public DeleteTopicsResult deleteTopics(Collection<String> topicNames,
                                           DeleteTopicsOptions options)
列出主题                                           
public ListTopicsResult listTopics(final ListTopicsOptions options)
查询主题的信息
public DescribeTopicsResult describeTopics(final Collection<String> topicNames, DescribeTopicsOptions options)
查看配置信息
public DescribeConfigsResult describeConfigs(Collection<ConfigResource> configResources, final DescribeConfigsOptions options)
修改配置信息
public AlterConfigsResult alterConfigs(Map<ConfigResource, Config> configs, final AlterConfigsOptions options)
增加分区
public CreatePartitionsResult createPartitions(Map<String, NewPartitions> newPartitions,
                                                   final CreatePartitionsOptions options)

验证主题

一般auto.create.topics.enable参数为false,不允许自动创建主题

Kafka broker端有参数 create.topic.policy.class.name 默认null,该参数提供一个入口验证主题创建的合法性

	需要自定义实现CreateTopicPolicy接口 如PolicyTest实现该接口然后在server.properties中配置create.topic.policy.class.name=org.apache.kafka.server.policy.PolicyTest
	
如此创建topic时,命名不规范会报错

分区

包括优先副本的选举,分区重分配,复制限流,修改副本因子

优先副本(preferred replica)的选举

分区使用多副本机制,其中leader副本对外提供读写,follower副本只进行消息的同步。若一个分区的leader副本不可用,那么就意味着整个分区变得不可用,此时则从剩余follower副本中选举一个新的leader

优先副本preferred replica:

优先副本是指在AR集合列表中的第一个副本。优先副本是为了能够治理负载失衡的情况,如下负载失衡 leader为0的分区有2个

Topic: topic1 PartitionCount:3 ReplicationFactor:3 Configs:
Topic: topic1 Partition: 0 Leader: 1 Replicas: 1,2,0 Isr: 1,0,2
Topic: topic1 Partition: 1 Leader: 0 Replicas: 2,0,1 Isr: 0,1,2
Topic: topic1 Partition: 2 Leader: 0 Replicas: 0,1,2 Isr: 0,1,2

如上主题topic1中分区0的AR集合Replicas为[1,2,0],那么分区0的优先副本即为1。理想情况下优先副本就是该分区的leader副本,故而优先副本也称preferred leader

Kafka要确保所有主题的优先副本在Kafka集群中均衡分布,如此保证leader均衡分布,若leader分布过于集中则集群负载不均衡

优先副本的选举是指通过一定方式促使优先副本被选举为leader副本,也叫分区平衡

Kafka中提供分区自动平衡的功能,broker端参数auto.leader.rebalance.enable,默认true,若开启分区自动平衡的功能,则Kafka的控制器会启动一个定时任务轮询所有的broker节点,计算每个broker节点的分区不平衡率**(broker的不平衡率=非优先副本的leader个数/分区总数)**是否超过leader.imbalance.per.broker.percentage参数配置的比值,默认10%,若超过设定的比值则会自动执行优先副本的选举动作以求分区平衡。执行周期由参数leader.imbalance.check.interval.seconds控制,默认300秒

broker端分区自动平衡相关参数

auto.leader.rebalance.enable:是否开启分区自动平衡功能 默认true开启:生产环境建议false,自动执行会引起客户端阻塞,导致不可用,建议手动再平衡
leader.imbalance.per.broker.percentage:broker节点分区不平衡率可容忍的最高比值 默认10% 超过则分区再平衡
leader.imbalance.check.interval.seconds:分区再平衡的执行周期,若分区不平衡且比值超过leader.imbalance.per.broker.percentage 才会再平衡,默认300秒

kafka-perferred-replica-election.sh 手动执行分区再平衡

kafka-perferred-replica-election.sh脚本提供了对分区leader副本进行重新平衡的功能。
此优先副本选举足够安全,客户端可自动感知分区leader副本的变化

bin/kafka-preferred-replica-election.sh --zookeeper localhost:2181

执行结果
Created preferred replica election path with __consumer_offsets-22,__consumer_offsets-30,__consumer_offsets-8
Successfully started preferred replica election for partitions Set(分区集合...)

直接执行kafka-perferred-replica-election.sh会将集群上所有的分区都执行一遍优先副本的选举操作。leader副本的转移是一项高成本工作,若要执行的分区数多会影响客户端。若集群中包含大量的分区,那么上面的这种方式有可能失效。
在优先副本的选举过程中,具体的元数据信息会被存入ZooKeeper的/admin/preferred_replica_election节点,若这些数据超过了ZooKeeper所允许的大小,则会选举失败。默认允许大小1MB

path-to-json-file参数批量对部分分区执行优先副本的选举操作

当面对大量分区的集群时,通过kafka-perferred-replica-election.sh脚本path-to-json-file参数指定一个JSON文件(保存需要执行优先副本选举的分区清单)来执行优先副本的选举操作

创建JSON文件test.json
{
	"partitions":[
		{
			"partition":0,
			"topic":"topic-test"
		},
        {
			"partition":1,
			"topic":"topic-test"
		}
	]
}

执行脚本bin/kafka-preferred-replica-election.sh --zookeeper localhost:2181 --path-to-json-file test.json

执行结果:成功将分区0和1进行优先副本的再选举
Created preferred replica election path with topic-test-0,topic-test-1
Successfully started preferred replica election for  partitions Set(topic-test-0,topic-test-1)

**注意:**生产环境使用path-to-json-file参数来分批,手动地执行优先副本的选举操作

分区重分配

Kafka分区分配存在的问题:

  • 多副本某个节点down下,则位于这个节点leader副本会移交到集群的其他follower副本。此时这个节点的分区副本都失效,但Kafka不会将这些失效的副本自动地迁移到集群中剩余的可用broker节点上
  • 当集群中新增broker节点时,只有新创建的主题分区才有可能被分配到这个节点上,而之前的主题分区并不会自动分配到新加入的节点中,导致新节点的负载和原先节点的负载之间严重不均衡

为了解决上述两个问题,需要让分区副本合理重分配,Kafka提供kafka-reassign-partitions.sh脚本来执行分区重分配的工作,它可以在集群扩容,broker节点失效的场景下对分区进行迁移

kafka-reassign-partitions.sh脚本执行步骤

  • 创建需要一个包含主题清单的JSON文件
  • 根据主题清单和broker节点清单生成重分配方案
  • 执行具体的重分配
当需要将brokerId为1的broker节点下线时,需将其上的分区副本迁移出去

1.创建一个JSON文件 test.json;文件内容为要进行分区重分配的主题清单 对于主题topic-test 如下
{
	"topics":[
		{
			"topic":"topic-test"
		}
	],
	"version":1
}
2.根据JSON文件和指定所要分配的broker节点列表来生成一份候选的重分配方案
bin/kafka-reassign-partitions.sh --zookeeper localhost:2181 --generate --topics-to-move-json-file test.json --broker-list 0,2
	--generate是该脚本的指令类型参数,相当于kafka-topics.sh的--create,它用来生成一个重分配的候选方案
	--topic-to-move-json用来指定分区重分配对应的主题清单文件的路径
	--broker-list用来指定所要分配的broker节点列表
执行结果:
	当前的分区副本分配情况的json格式内容 保存起来以后回滚分配
	Crrent partition replica assignment
	{...}
	重分配的候选方案,此时并没有执行重分配,只是生成执行重分配的json格式内容
	Proposed partition reassignment configuration
	将该方案保存在test1.json文件中
3.执行具体的重分配动作
bin/kafka-reassign-partitions.sh --zookeeper localhost:2181 --execute --reassignment-json-file test1.json
此时会按test1.json文件中的分区分配方案进行重分配!
	--execute 指令类型参数,执行重分配动作
	--reassignment-json-file test1.json 指定分区重分配方案的文件路径

查看分区重分配的进度

bin/kafka-reassign-partitions.sh --zookeeper localhost:2181 --verify --reassignment-json-file test1.json

分区重分配的基本原理:本质在于数据复制

通过控制器为每个分区添加新副本(增加副本因子),新的副本将从分区的leader副本哪里复制所有的数据(数据迁移,耗费时间,空间,带宽)
控制器将旧副本从副本清单里移除(恢复为原先的副本因子数)
注意:重分配过程中要确保由足够的空间,且执行后若leader负载不均衡可使用优先副本的选举重新选举leader

分区重分配对集群的性能有很大的影响,需要占用额外的资源,如网络和磁盘。实际应该降低重分配的粒度,分成多个小批次来执行

注意:若要将某个broker下线,最好再分区重分配之前关闭或重启该broker。如此这个broker不存在任何分区的leader节点。减少broker间的流量复制

复制限流

若集群中某个主题或某个分区的流量在某段时间内特别大,那么分区重分配时只靠减少粒度不足以应对,此时就需要限流机制,可对副本间的复制流量进行限制保证重分配期间整体服务不受影响

副本间复制限流的方式

  • kafka-config.sh脚本
  • kafka-reassign-partitions.sh脚本

kafka-config.sh脚本限流:动态配置的方式达到限流
broker端参数

follower.replication.throttled.rate:设置follower副本复制的速度
leader.replication.throttled.rate:设置leader副本传输的速度 
两者配置一般值相同,单位B/s

设置传输速度1kb/s
bin/kafka-configs.sh --zookeeper localhost:2181 --entity-type brokers --entity-name 1 --alter --add-config follower.replication.throttled.rate=1024,leader.replication.throttled.rate=1024
结果
Completed Updating config for entity: brokers '1'.

主题端参数

follower.replication.throttled.replicas:被限制速度的主题所对应的的follower副本列表 [0:1,1:2,2:0] 即[分区n:follower副本broker]
leader.replication.throttled.replicas:被限制速度的主题所对应的的leader副本列表[0:0,1:1,2:2] 即[分区n:leader副本brokerId]

kafka-reassign-partitions.sh脚本限流:需要一个throttle参数 推荐此方法 本质也是第一个方法的四个参数

bin/kafka-reassign-partitions.sh --zookeeper localhost:2181 --execute --reassignment-json-file test1.json --throttle 10 
限流的速度上限10B/s 以上命名可重复执行提高限流的速度上限
需要周期性执行查看进度的命令直到重分配完成,这样可确保限流设置被移除
	bin/kafka-reassign-partitions.sh --zookeeper localhost:2181 --verify --reassignment-json-file test1.json

修改副本因子

详情看分区重分配

bin/kafka-reassign-partitions.sh --zookeeper localhost:2181 --execute --reassignment-json-file test1.json

json格式:
{
    "version": 1,
    "partitions": [
        {
            "topic": "topic-throttle",
            "partition": 1,
            "replicas": [
                2,
                0
                //1.此处新增一个副本
            ],
            "log_dirs": [
                "any",
                "any"
                //2.此处对应要新增any log_dirs参数的数量和replicas的数量保持一致!
            ]
        },
        {
            "topic": "topic-throttle",
            "partition": 0,
            "replicas": [
                0,
                2
            ],
            "log_dirs": [
                "any",
                "any"
            ]
        },
        {
            "topic": "topic-throttle",
            "partition": 2,
            "replicas": [
                0,
                2
            ],
            "log_dirs": [
                "any",
                "any"
            ]
        }
    ]
}

副本因子可以增加也可以减少,replicas参数每多一个副本brokerId,log_dirs参数就多一个any

分区数的选择

kafka性能测试

生产者性能测试kafka-producer-perf-test.sh,消费者性能测试kafka-consumer-perf-test.sh

kafka-producer-perf-test.sh

向主题topic-test 发送100万条消息,每条消息大小为1024B,生产者对应acks参数为1
bin/kafka-producer-perf-test.sh --topic topic-test --num-records 1000000 --record-size 1024 --throughput -1 --producer-props bootstrap.servers=localhost:9092 acks=1
执行结果
184756 records sent, 36951.2 records/sec (36.09 MB/sec), 711.8 ms avg latency, 1298.0 max latency.
381240 records sent, 76248.0 records/sec (74.46 MB/sec), 403.8 ms avg latency, 538.0 max latency.
386370 records sent, 77274.0 records/sec (75.46 MB/sec), 397.8 ms avg latency, 461.0 max latency.
1000000 records sent, 64094.346879 records/sec (62.59 MB/sec), 457.14 ms avg latency, 1298.00 ms max latency, 400 ms 50th, 786 ms 95th, 1161 ms 99th, 1286 ms 99.9th.
已发送1000000条记录,64094.346879条记录/秒(62.59 MB /秒),457.14 ms平均延迟,1298.00 ms最大延迟,400 ms 50%,786 ms 95%,1161 ms 99%,1286 ms 99.9%。
	records send 消息总数
	records/sec 每秒发送的消息总数来统计吞吐量
	MB/sec 每秒发送的消息大小来统计吞吐量
	avg latency 消息处理的平均耗时
	max latency 消息处理的最大耗时
	50th,99.9th等 表示50%,99.9%的消息处理耗时

--topic:指定目标主题
--num-records:指定发送消息的总条数
--record-size:设置每条消息的字节数单位B
--producer-props:指定生产者的配置,空格分隔多组配置
--producer.config:指定生产者的配置文件
--throghput:限流控制,值小于0不限流,大于0,当发送的吞吐量大于该值时就会被阻塞一段时间 该参数限制的是77274.0 records/sec (75.46 MB/sec) 单位b/sec
--print-metrics:提示更多性能指标

kafka-consumer-perf-test.sh

bin/kafka-consumer-perf-test.sh --topic topic-test --messages 1000000 --broker-list localhost:9092

start.time, end.time, data.consumed.in.MB, MB.sec, data.consumed.in.nMsg, nMsg.sec, rebalance.time.ms, fetch.time.ms, fetch.MB.sec, fetch.nMsg.sec
WARNING: Exiting before consuming the expected number of messages: timeout (10000 ms) exceeded. You can use the --timeout option to increase the timeout.
2020-03-04 15:10:58:531, 2020-03-04 15:11:04:657, 976.5625, 159.4127, 1000000, 163238.6549, 16, 6110, 159.8302, 163666.1211

start.time 起始运行时间
end.time 结束运行时间
data.consumed.in.MB 单位MB,消费的消息总量
MB.sec 按字节大小计算的消费吞吐量
data.consumed.in.nMsg:消费的消息总数
nMsg.sec 按消息个数计算的吞吐量
rebalance.time.ms 再平衡的时间 单位ms
fetch.time.ms 拉取消息的持续时间
fetch.MB.sec 每秒拉取消息的字节大小
fetch.nMsg.sec每秒拉取消息的个数
其中fetch.time.ms=end.time-start.time-rebalance.time.ms

合适的分区数

分区数并非越多越好,分区数对kafka性能提升拥有一个阈值

分区数的上限和linux的文件描述符的限制有关通过ulimit -n 65536将上限提高,或修改limits.conf文件

root soft nofile 65535
root hard nofile 65535

不同环境的分区数阈值不同,最大效率需要进行环境测试

分区在进行leader角色切换时会不可用

broker节点数不多时,建议将分区数设定为集群中broker的倍数,如3,6,9