图解Kafka分区副本同步限流机制三部曲(源码原理篇+测试用例 )

本文深入探讨Kafka的分区副本限流机制,包括如何设置和判断副本是否限流,以及限流阈值的设定。通过具体测试用例分析了Leader和Follower限流的影响,揭示了多副本同步时的限流行为,展示了如何调整配置以控制数据同步速度。
摘要由CSDN通过智能技术生成

replica.alter.log.dirs.io.max.bytes.per.second broker内部目录之间迁移数据流量限制功能,限制数据拷贝从一个目录到另外一个目录带宽上限

leader.replication.throttled.replicas: leader端的副本限流

follower.replication.throttled.replicas: follower端的副本限流

就算你不记得也没有关系,那我们今天来好好讲一讲这一块的内容

如何使某个副本需要被限流


首先我们看下判断Follower是否应该被限流的判断逻辑

/**

  • 为避免ISR抖动,我们仅在跟随者上的副本处于限制副本列表中、超出配额、且副本不同步时候对其进行限流

*/

private def shouldFollowerThrottle(quota: ReplicaQuota, fetchState: PartitionFetchState, topicPartition: TopicPartition): Boolean = {

!fetchState.isReplicaInSync && quota.isThrottled(topicPartition) && quota.isQuotaExceeded

}

被限流的条件如下

  1. 副本不在ISR列表中

  2. 该副本在限流配置列表中

  3. 超过限流阈值了

这里我们主要分析一下,如何才能在限流配置列表中

private def shouldFollowerThrottle(quota: ReplicaQuota, fetchState: PartitionFetchState, topicPartition: TopicPartition): Boolean = {

!fetchState.isReplicaInSync && quota.isThrottled(topicPartition) && quota.isQuotaExceeded

}

override def isThrottled(topicPartition: TopicPartition): Boolean = {

val partitions = throttledPartitions.get(topicPartition.topic)

if (partitions != null)

(partitions eq AllReplicas) || partitions.contains(topicPartition.partition)

else false

}

上面的ConcurrentHashMap throttledPartitions 就是所有需要被限流的副本列表,那么是在哪里被赋值的呢?

ConfigHandler#processConfigChanges

def processConfigChanges(topic: String, topicConfig: Properties): Unit = {

// Validate the configurations.

val configNamesToExclude = excludedConfigs(topic, topicConfig)

updateLogConfig(topic, topicConfig, configNamesToExclude)

def updateThrottledList(prop: String, quotaManager: ReplicationQuotaManager) = {

if (topicConfig.containsKey(prop) && topicConfig.getProperty(prop).length > 0) {

val partitions = parseThrottledPartitions(topicConfig, kafkaConfig.brokerId, prop)

println(prop+“本机:”+kafkaConfig.brokerId+" Topic"+topic+“; 需要限流的分区有:”+partitions.mkString(" "))

quotaManager.markThrottled(topic, partitions)

debug(s"Setting $prop on broker ${kafkaConfig.brokerId} for topic: $topic and partitions $partitions")

} else {

quotaManager.removeThrottle(topic)

debug(s"Removing $prop from broker ${kafkaConfig.brokerId} for topic $topic")

}

}

// 这里,更新限流副本

updateThrottledList(LogConfig.LeaderReplicationThrottledReplicasProp, quotas.leader)

updateThrottledList(LogConfig.FollowerReplicationThrottledReplicasProp, quotas.follower)

if (Try(topicConfig.getProperty(KafkaConfig.UncleanLeaderElectionEnableProp).toBoolean).getOrElse(false)) {

kafkaController.enableTopicUncleanLeaderElection(topic)

}

}

这段代码是在修改了动态配置中的topic节点的时候会被触发的,关于动态配置可以看我之前的文章 [Kafka中的动态配置源码分析

]( )

这里的代码简单描述下

  1. 检查 动态配置 中是否存在配置 leader.replication.throttled.replicasfollower.replication.throttled.replicas

  2. 如果存在,则需要解析一下配置Value,解析得到的Value就是需要被限流的副本列表,将它写到内存中。

  3. 如果不存在,则需要把当前的限流副本列表清空。

具体的解析逻辑如下

ConfigHandler#parseThrottledPartitions

def parseThrottledPartitions(topicConfig: Properties, brokerId: Int, prop: String): Seq[Int] = {

val configValue = topicConfig.get(prop).toString.trim

ThrottledReplicaListValidator.ensureValidString(prop, configValue)

configValue match {

case “” => Seq()

case “*” => AllReplicas

case _ => configValue.trim

.split(“,”)

.map(_.split(“:”))

.filter(_ (1).toInt == brokerId) //Filter this replica

.map(_ (0).toInt).toSeq //convert to list of partition ids

}

}

  1. 如果为空就没有需要限流的

  2. 如果是*表示所有副本都需要限流

  3. 配置值的格式为:分区号:副本所在BrokerId,分区号:副本所在BrokerId 并过滤一下副本所在BrokerId=自己的BrokerId

例如: 1:102,2:0,3:0 在当前 BrokerID=102 的集群上最终解析出来需要限流的副本为 1 , 只需要解析跟自己相关的副本就行了。

在这里插入图片描述

具体限流需要限制在多少

上面只是讲了怎么将分区副本设置为需要限流, 但是并没有设置限流多少鸭!就算上面你设置了,这里没有设置限流多少,那么默认的限流值就是 Long.MAXVALUE 约等于没有限流。

那么如何设置限流的流速呢?

请看下面代码, 这个是 在修改了Broker的动态配置之后就会调用的方法, 关于动态配置可以看我之前的文章 [Kafka中的动态配置源码分析

]( )

BrokerConfigHandler#processConfigChanges

class BrokerConfigHandler(private val brokerConfig: KafkaConfig,

private val quotaManagers: QuotaManagers) extends ConfigHandler with Logging {

def processConfigChanges(brokerId: String, properties: Properties): Unit = {

def getOrDefault(prop: String): Long = {

if (properties.containsKey(prop))

properties.getProperty(prop).toLong

else

DefaultReplicationThrottledRate

}

if (brokerId == C

  • 17
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值