Kafka引入副本机制的目的主要是为了增加kafka集群的高可用性。Kafka实现副本机制后,每个分区可以有多个副本,并且会从其副本集合(AR)中选举出一个Leader副本,负责所有的读写请求,剩余作为follower副本,follower副本会从leader副本fetch 消息到自己的log,以防止leader挂了,其余broker上的follower可以选举为leader继续对外提供服务。一般情况下,同一个分区的多个副本会均匀分配到集群中不同broker,如果一个分区的全部副本都在同一个broker上,那么该broker出现故障后,就会导致整个分区不可用。
一个分区的leader副本中会维护自身以及所有follower的状态,但是follower副本只是维护自己的状态
一Replica核心字段
brokerId:Int 表示该副本属于哪一个broker
partition:Partition 表示属于哪一个分区的副本
highWatermarkMetadata:LogOffsetMetadata 用来记录HighWatermark
(HW)的值(最高水位线)。消费者只能获取HighWatermark之前的消息,后面的消息对消费者不可见。该字段是由leader副本维护的,更新的时机是消息被ISR同步列表的副本全部成功同步,即消息被提交成功
logEndOffsetMetadata:LogOffsetMetadata 对于本地副本,此字段主要记录追加到log的最新消息的offset,可以直接从Log.nextOffsetMeta
data获取;对于远程副本,含义相同但是需要其他broker发送请求来更新这个值,并不能从本地直接获取到
log: Log 副本对应的Log对象,远程副本此字段为空
lastCaughtUpTimeMsUnderlying:AtomicLong 用于记录follower上一次赶上leader的时间戳
二 Replica重要方法
2.1 isLocal 根据日志对象是否为空判断该副本是本地副本还是远程副本
def isLocal: Boolean = {
log match {
case Some(l) =>true
case None => false
}
}
2.2 logEndOffset 获取本地或者远程副本的LEO
private def logEndOffset_=(newLogEndOffset: LogOffsetMetadata) {
// 对于本地副本不能直接更新LEO,其LEO由Log的logEndOffsetMetadata字段决定
if (isLocal) {
throw new KafkaException("Should not set log end offset on partition [%s,%d]'s local replica %d".format(topic, partitionId, brokerId))
} else {
// 如果是远程副本,LEO是通过请求进行更新的
logEndOffsetMetadata = newLogEndOffset
trace("Setting log end offset for replica %d for partition [%s,%d] to [%s]"
.format(brokerId, topic, partitionId, logEndOffsetMetadata))
}
}
def logEndOffset =
// 对于本地副本不能直接更新LEO,其LEO由Log的logEndOffsetMetadata字段决定
if (isLocal)
log.get.logEndOffsetMetadata
else // 远程副本应该从leader处通过LEO的请求更新
logEndOffsetMetadata
2.3 highWatermark 更新HighWatermark,只有本地才可以
def highWatermark_=(newHighWatermark: LogOffsetMetadata) {
// 只有本地副本才可以更新HighWatermark
if (isLocal) {
highWatermarkMetadata = newHighWatermark
trace("Setting high watermark for replica %d partition [%s,%d] on broker %d to [%s]"
.format(brokerId, topic, partitionId, brokerId, newHighWatermark))
} else {
throw new KafkaException("Should not set high watermark on partition [%s,%d]'s non-local replica %d".format(topic, partitionId, brokerId))
}
}