1.分区数确定
创建一个只有 1 个分区的 topic
测试这个 topic 的 producer 吞吐量和consumer 吞吐量。
假设他们的值分别是 Tp 和 Tc,单位可以是 MB/s。
然后假设总的目标吞吐量是Tt,那么分区数=Tt / min(Tp,Tc)
例如:producer 吞吐量=20m/s;consumer 吞吐量=50m/s,期望吞吐量 100m/s;
分区数=100 / 20 =5 分区
https://blog.csdn.net/weixin_42641909/article/details/89294698
分区数并不是越多越好,一般分区数不要超过集群机器数量。分区数越多占用内存越大(ISR等),一个节点集中的分区也就越多,当它宕机的时候,对系统的影响也就越大。
分区数一般设置为:3-10 个
*producer消息发送分区选择
默认情况下,如果key不为空,Kafka会根据传递消息的key来进行分区的分配
def partition(key: Any, numPartitions: Int): Int = {
Utils.abs(key.hashCode) % numPartitions
}
*key为null时,从缓存中获取分区id或者随机取一个
if(key == null) { // 如果没有指定key
val id = sendPartitionPerTopicCache.get(topic) // 先看看Kafka有没有缓存的现成的分区Id
id match {
case Some(partitionId) =>
partitionId // 如果有的话直接使用这个分区Id就好了
case None => // 如果没有的话,
val availablePartitions = topicPartitionList.filter(_.leaderBrokerIdOpt.isDefined) //找出所有可用分区的leader所在的broker
if (availablePartitions.isEmpty)
throw new LeaderNotAvailableException("No leader for any partition in topic " + topic)
val index = Utils.abs(Random.nextInt) % availablePartitions.size // 从中随机挑一个
val partitionId = availablePartitions(index).partitionId
sendPartitionPerTopicCache.put(topic, partitionId) // 更新缓存以备下一次直接使用
partitionId
}
}
2.producer发送消息分区分配策略
在 Kafka 内部存在两种默认的分区分配策略:Range 和 RoundRobin。
Range 是默认策略。Range 是对每个Topic 而言的(即一个Topic 一个Topic 分),首先对同一个Topic 里面的分区按照序号进行排序,并对消费者按照字母顺序进行排序。然后用Partitions 分区的个数除以消费者线程的总数来决定每个消费者线程消费几个分区。如果除不尽,那么前面几个消费者线程将会多消费一个分区。
例如:我们有 10 个分区,两个消费者(C1,C2),3 个消费者线程,10 / 3 = 3 而且除不尽。
C1-0 将消费 0, 1, 2, 3 分区
C2-0 将消费 4, 5, 6 分区
C2-1 将消费 7, 8, 9 分区
RoundRobin:前提:同一个Consumer Group里面的所有消费者的num.streams(消费者消费线程数)必须相等;每个消费者订阅的主题必须相同。
:将所有主题分区组成 TopicAndPartition 列表,然后对 TopicAndPartition 列表按照 hashCode 进行排序,最后按照轮询的方式发给每一个消费线程