我们的kafka源码分享已经进行过很多期了,主要的内容也都分享的差不多了,那么那么在今后的分享中,主要集中在kafka性能优化和使用
Kafka集群中的其中一个Broker会被选举为Controller,主要负责Partition管理和副本状态管理,也会执行类似于重分配Partition之类的管理任务。如果当前的Controller失败,会从其他正常的Broker中重新选举Controller。
进入KafkaController.scala文件看到如下代码:
class KafkaController(val config : KafkaConfig, zkClient: ZkClient, val brokerState: BrokerState) extends Logging with KafkaMetricsGroup {
this.logIdent = "[Controller " + config.brokerId + "]: "
private var isRunning = true
private val stateChangeLogger = KafkaController.stateChangeLogger
val controllerContext = new ControllerContext(zkClient, config.zkSessionTimeoutMs)
val partitionStateMachine = new PartitionStateMachine(this)
val replicaStateMachine = new ReplicaStateMachine(this)
private val controllerElector = new ZookeeperLeaderElector(controllerContext, ZkUtils.ControllerPath, onControllerFailover,
onControllerResignation, config.brokerId)
// have a separate scheduler for the controller to be able to start and stop independently of the
// kafka server
private val autoRebalanceScheduler = new KafkaScheduler(1)
var deleteTopicManager: TopicDeletionManager = null
val offlinePartitionSelector = new OfflinePartitionLeaderSelector(controllerContext, config)
private val reassignedPartitionLeaderSelector = new ReassignedPartitionLeaderSelector(controllerContext)
private val preferredReplicaPartitionLeaderSelector = new PreferredReplicaPartitionLeaderSelector(controllerContext)
private val controlledShutdownPartitionLeaderSelector = new ControlledShutdownLeaderSelector(controllerContext)
private val brokerRequestBatch = new ControllerBrokerRequestBatch(this)
private val partitionReassignedListener = new PartitionsReassignedListener(this)
private val preferredReplicaElectionListener = new PreferredReplicaElectionListener(this)
在KafkaController类中定义了很多属性,我们先重点了解下面的PartitionLeaderSelector对象,主要是为分区选举出leader broker,该trait只定义了一个方法selectLeader,接收一个TopicAndPartition对象和一个LeaderAndIsr对象。TopicAndPartition表示要选leader的分区,而第二个参数表示zookeeper中保存的该分区的当前leader和ISR记录。该方法会返回一个元组包括了推举出来的leader和ISR以及需要接收LeaderAndISr请求的一组副本。
trait PartitionLeaderSelector {
def selectLeader(topicAndPartition: TopicAndPartition, currentLeaderAndIsr: LeaderAndIsr): (LeaderAndIsr, Seq[Int])
}
通过我们上面的代码,可以看到在KafkaController中共定义了五种selector选举器:
- 1、NoOpLeaderSelector
- 2、OfflinePartitionLeaderSelector
- 3、ReassignedPartitionLeaderSelector
- 4、PreferredReplicaPartitionLeaderSelector
- 5、ControlledShutdownLeaderSelector
我们在解释这五个选择器之前,先了解一下在Kafka中Partition的四种状态:
- NonExistentPartition —— 这个状态表示该分区要么没有被创建过或曾经被创建过但后面被删除了。
- NewPartition —— 分区创建之后就处于NewPartition状态。在这个状态中,分区应该已经分配了副本,但是还没有选举出leader和ISR。
- OnlinePartition —— 一旦分区的leader被推选出来,它就处于OnlinePartition状态。
- OfflinePartition —— 如果leader选举出来后,leader broker宕机了,那么该分区就处于OfflinePartition状态。
四种状态的转换关系如下:
NonExistentPartition -> NewPartition
- 首先将第一个可用的副本broker作为leader broker并把所有可用的副本对象都装入ISR,然后写leader和ISR信息到zookeeper中保存
- 对于这个分区而言,发送LeaderAndIsr请求到每个可用的副本broker,以及UpdateMetadata请求到每个可用的broker上
OnlinePartition, OfflinePartition -> OnlinePartition
为该分区选取新的leader和ISR以及接收LeaderAndIsr请求的一组副本,然后写入leader和ISR信息到zookeeper中保存。
NewPartition, OnlinePartition -> OfflinePartition
标记分区状态为离线(offline)。
OfflinePartition -> NonExistentPartition
离线状态标记为不存在分区,表示该分区失败或者被删除。
在介绍完最基本的概念之后,下面我们将重点介绍上面提到过的五种选举器:
1、ReassignedPartitionLeaderSelector
从可用的ISR中选取第一个作为leader,把当前的ISR作为新的ISR,将重分配的副本集合作为接收LeaderAndIsr请求的副本集合。
2、PreferredReplicaPartitionLeaderSelector
如果从assignedReplicas取出的第一个副本就是分区leader的话,则抛出异常,否则将第一个副本设置为分区leader。
3、ControlledShutdownLeaderSelector
将ISR中处于关闭状态的副本从集合中去除掉,返回一个新新的ISR集合,然后选取第一个副本作为leader,然后令当前AR作为接收LeaderAndIsr请求的副本。
4、NoOpLeaderSelector
原则上不做任何事情,返回当前的leader和isr。
5、OfflinePartitionLeaderSelector
从活着的ISR中选择一个broker作为leader,如果ISR中没有活着的副本,则从assignedReplicas中选择一个副本作为leader,leader选举成功后注册到Zookeeper中,并更新所有的缓存。
所有的leader选择完成后,都要通过请求把具体的request路由到对应的handler处理。目前kafka并没有把handler抽象出来,而是每个handler都是一个函数,混在KafkaApi类中。
其实也就是如下的代码:
def handle(request: RequestChannel.Request) {
try{
trace("Handling request: " + request.requestObj + " from client: " + request.remoteAddress)
request.requestId match {
case RequestKeys.ProduceKey => handleProducerRequest(request) // producer
case RequestKeys.FetchKey => handleFetchRequest(request) // consumer
case RequestKeys.OffsetsKey => handleOffsetRequest(request)
case RequestKeys.MetadataKey => handleTopicMetadataRequest(request)
case RequestKeys.LeaderAndIsrKey => handleLeaderAndIsrRequest(request) //成为leader或follower设置同步副本组信息
case RequestKeys.StopReplicaKey => handleStopReplicaRequest(request)
case RequestKeys.UpdateMetadataKey => handleUpdateMetadataRequest(request)
case RequestKeys.ControlledShutdownKey => handleControlledShutdownRequest(request) //shutdown broker
case RequestKeys.OffsetCommitKey => handleOffsetCommitRequest(request)
case RequestKeys.OffsetFetchKey => handleOffsetFetchRequest(request)
case requestId => throw new KafkaException("Unknown api code " + requestId)
}
} catch {
case e: Throwable =>
request.requestObj.handleError(e, requestChannel, request)
error("error when handling request %s".format(request.requestObj), e)
} finally
request.apiLocalCompleteTimeMs = SystemTime.milliseconds
}
这里面的每个请求在上面给出的链接的文章中都有过解释说明,在这里不多解释。
RequestKeys.LeaderAndIsr详细分析
在上面的代码中咱们看到ReequestKeys.LeaderAndlst对应的方法其实是KeyhandleLeaderAndIsrRequest。
def handleLeaderAndIsrRequest(request: RequestChannel.Request) {
// ensureTopicExists is only for client facing requests
// We can't have the ensureTopicExists check here since the controller sends it as an advisory to all brokers so they
// stop serving data to clients for the topic being deleted
val leaderAndIsrRequest = request.requestObj.asInstanceOf[LeaderAndIsrRequest]
try {
val (response, error) = replicaManager.becomeLeaderOrFollower(leaderAndIsrRequest, offsetManager)
val leaderAndIsrResponse = new LeaderAndIsrResponse(leaderAndIsrRequest.correlationId, response, error)
requestChannel.sendResponse(new Response(request, new BoundedByteBufferSend(leaderAndIsrResponse)))
} catch {
case e: KafkaStorageException =>
fatal("Disk error during leadership change.", e)
Runtime.getRuntime.halt(1)
}
}
将request.requestObj转换成LeaderAndIstRequest对象类型。
流程图说明
1、如果请求中controllerEpoch小于当前最新的controllerEpoch,则直接返回ErrorMapping.StaleControllerEpochCode。
2、如果partitionStateInfo中的leader epoch大于当前ReplicManager中存储的(topic, partitionId)对应的partition的leader epoch,则:
2.1、如果当前brokerid(或者说replica id)在partitionStateInfo中,则将该partition及partitionStateInfo存入一个名为partitionState的HashMap中。
否则说明该Broker不在该Partition分配的Replica list中,将该信息记录于log中
3、如果partitionStateInfo中的leader epoch小于当前ReplicManager则将相应的Error code(ErrorMapping.StaleLeaderEpochCode)存入Response中。
4、筛选出partitionState中Leader与当前Broker ID相等的所有记录存入partitionsTobeLeader中,其它记录存入partitionsToBeFollower中。
如果partitionsTobeLeader不为空,则对其执行makeLeaders方。
如果partitionsToBeFollower不为空,则对其执行makeFollowers方法。
相关推荐
7. **连接器(Connectors)和流处理(Kafka Streams)**:Kafka Connect允许用户方便地集成其他系统,如数据库,而Kafka Streams则提供了一种在Kafka之上进行流处理的API,使得实时分析和复杂事件处理变得简单。...
Kafka技术内幕:图文详解Kafka源码设计与实现 PDF 下载 Kafka技术内幕:图文详解Kafka源码设计与实现 PDF 下载
本书以0.10版本的源码为基础,深入分析了Kafka的设计与实现,包括生产者和消费者的消息处理流程,新旧消费者不同的设计方式,存储层的实现,协调者和控制器如何确保Kafka集群的分布式和容错特性,两种同步集群工具...
《Kafka技术内幕:图文详解Kafka源码设计与实现》是一本深入解析Apache Kafka的专著,旨在帮助读者理解Kafka的核心设计理念、内部机制以及源码实现。这本书籍覆盖了大数据处理领域的关键知识点,通过丰富的图表和...
### Kafka工作原理详解 #### 一、Kafka的角色与组件 Kafka作为一款分布式消息系统,在实际应用中涉及多种角色及组件,它们协同工作确保消息的高效传递。 1. **Broker**:Kafka集群的基本单元,一个Broker可以视为...
《Kafka技术内幕:图文详解Kafka源码设计与实现》是郑奇煌在2017年11月出版的一本深入解析Apache Kafka的技术专著。这本书详细介绍了Kafka的核心概念、工作原理以及源码分析,旨在帮助读者理解并掌握这个分布式流...
《Kafka技术内幕:图文详解Kafka源码设计与实现》这本书深入剖析了Apache Kafka这一分布式消息系统的内在机制,旨在帮助读者理解Kafka的核心设计理念,掌握其实现方式,并能运用到实际项目中。以下是该书可能涵盖的...
Kafka参数配置详解 Kafka是一种流行的分布式流处理平台,用于构建实时数据管道和事件驱动的架构。为了确保Kafka集群的稳定运行和高性能,需要正确地配置Kafka参数。本文将详细介绍Kafka的参数配置,包括系统参数、...
### Kafka学习之路——详解Kafka原理与架构 #### 一、Kafka简介 Kafka是一款由LinkedIn开发并开源的消息队列系统,它主要用于处理实时数据流,并能够支持在线和离线的日志处理需求。Kafka的基本特性包括高吞吐量、...
本书以0.10版本的源码为基础,深入分析了Kafka的设计与实现,包括生产者和消费者的消息处理流程,新旧消费者不同的设计方式,存储层的实现,协调者和控制器如何确保Kafka集群的分布式和容错特性,两种同步集群工具...
19. advertised.host.name和advertised.port:当Kafka集群位于防火墙后或使用了负载均衡器时,应使用这两个参数来指定客户端连接的实际主机名和端口。 了解并正确设置这些参数,有助于确保Kafka集群的性能和可靠性...
Kafka3.0是一个在分布式系统中广泛使用的消息队列系统,主要用于构建实时数据管道和流式应用程序。它的客户端命令以及核心配置文件是其操作的核心,而spring集成和webflux集成则可以将Kafka3.0与主流的Java开发框架...
- **ZooKeeper**:负责管理Kafka集群的元数据,如主题的配置信息、分区的状态等,同时负责控制器的选举,确保Kafka集群的高可用性。 - **Broker**:作为Kafka的服务节点,负责接收来自Producer的消息,并存储这些...
《图解 Kafka 之实战指南》是一本深入解析Apache Kafka的实用书籍,旨在帮助读者理解和掌握这个分布式消息系统的精髓。Kafka是一个高吞吐、低延迟的开源流处理平台,常用于实时数据管道和流应用的构建。在这个实战...
《Kafka技术内幕》这本书深入剖析了Apache Kafka这一分布式流处理平台的设计原理和实现细节,旨在帮助读者理解Kafka的核心机制,并能有效地运用到实际项目中。以下是对Kafka源码设计与实现的一些关键知识点的详细...
### Kafka配置安装详解 #### 一、环境搭建与配置 Kafka是一款开源的消息队列中间件,被广泛应用于大数据处理领域。本篇文章将详细介绍如何在本地环境中安装并配置Kafka,以及进行基本的操作演示。 ##### 环境要求...
Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的...
大数据技术之Kafka详解 本文将对Kafka的概念、架构、特点和应用场景进行详细的解释。 Kafka的定义 Kafka是一个分布式的基于发布/订阅模式的消息队列(Message Queue),主要应用于大数据实时处理领域。 消息队列...
《Kafka数据可靠性机制详解》 Kafka作为一个分布式流处理平台,其数据可靠性是系统稳定性和可用性的重要保障。在深入探讨Kafka的数据可靠性机制之前,我们首先要理解Kafka的基本架构。Kafka由生产者、消费者和 ...