Kafka集群是由若干个broker组成的,启动kafka集群就是将集群中的broker启动并正常运行。broker与broker之间、broker与生成者之间、broker与消费者之间都存在各种交互。下面简单介绍一下broker的启动流程。

启动broker的脚本:

nohup ./bin/kafka-server-start.sh config/server.properties &

其中,脚本文件kafka-server-start.sh启动的操作如下:

exec $base_dir/kafka-run-class.sh $EXTRA_ARGS kafka.Kafka "$@"

最终执行的是kafka.Kafka这个类,kafka.Kafka的代码如下:

object Kafka extends Logging {

  def main(args: Array[String]): Unit = {
    ......
  
    try {
      val props = Utils.loadProps(args(0))
      val serverConfig = new KafkaConfig(props)
      KafkaMetricsReporter.startReporters(serverConfig.props)
      val kafkaServerStartable = new KafkaServerStartable(serverConfig)

      // attach shutdown handler to catch control-c
      Runtime.getRuntime().addShutdownHook(new Thread() {
        override def run() = {
          kafkaServerStartable.shutdown
        }
      })

      kafkaServerStartable.startup
      kafkaServerStartable.awaitShutdown
    }
    catch {
      case e: Throwable => fatal(e)
    }
    System.exit(0)
  }
}

通过上面的代码可以看出,代码通过执行kafkaServerStartable.startup来启动系统。KafkaServerStartable的启动代码如下:

class KafkaServerStartable(val serverConfig: KafkaConfig) extends Logging {
  private val server = new KafkaServer(serverConfig)

  def startup() {
    try {
      server.startup()
      AppInfo.registerInfo()
    }
    catch {
      ......
    }
  }
......
}

从上面的代码可以看出,KafkaServerStartable的启动函数主要是封装了KafkaServer的启动函数startup()。下面我们就一起来看一下KafkaServer的代码结构。

class KafkaServer(val config: KafkaConfig, time: Time = SystemTime) extends Logging with KafkaMetricsGroup {
  this.logIdent = "[Kafka Server " + config.brokerId + "], "
  private var isShuttingDown = new AtomicBoolean(false)
  private var shutdownLatch = new CountDownLatch(1)
  private var startupComplete = new AtomicBoolean(false)
  val brokerState: BrokerState = new BrokerState
  val correlationId: AtomicInteger = new AtomicInteger(0)
  var socketServer: SocketServer = null
  var requestHandlerPool: KafkaRequestHandlerPool = null
  var logManager: LogManager = null
  var offsetManager: OffsetManager = null
  var kafkaHealthcheck: KafkaHealthcheck = null
  var topicConfigManager: TopicConfigManager = null
  var replicaManager: ReplicaManager = null
  var apis: KafkaApis = null
  var kafkaController: KafkaController = null
  val kafkaScheduler = new KafkaScheduler(config.backgroundThreads)
  var zkClient: ZkClient = null
  ......
}

KafkaServer的类中包含了系统运行需要的各个模块,下面介绍一下主要模块的功能。

      1、SocketServer:broker的通信模块。用来和其它broker、生成者、消费者发送、接收消息。  首先会创建一个Acceptor线程监听默认端口9092的socket请求,当有新的连接加入时会创建一个对应的SocketChannel以轮询的方式转发给Processor线程中的某一个,并由其处理该SocketChannel接下来的请求,会将请求放置在RequestChannel的请求队列中。当Processor监听到SocketChannel请求的响应时,会将响应请求从RequestChannel的相应队列中取出来发送给客户端。

     2、KafkaRequestHandlerPool:处理socket请求的线程池。会将socket请求从队列中取出来然后调用KafkaApis完成业务逻辑的处理,并将处理的结果放回到RequestChannel的响应队列。

     3、LogManager:Kafka的日志管理模块。主要是删除过期数据和冗余数据、刷新脏数据,对日志文件进行Checkpoint和日志合并

     4、ReplicationManager:Kafka的副本管理模块。主要是针对Topic的分区副本数据进行管理,包括副本leader和ISR状态的变化、副本的删除等。

     5、OffsetManager:Kafka的偏移量offset的管理模块。主要是偏移量offset的保存和读取。

     6、KafkaScheduler:Kafka的后台任务调度资源池。为LogManager、ReplicationManager、OffsetManager等模块提供线程调度服务。

     7、KafkaApis:kafka的业务逻辑实现层。根据不同的Request处理不同的请求。处理去请求包括ProduceKey、FetchKey、OffsetsKey、MetadataKey、LeaderAndIsrKey、StopReplicaKey、UpdateMetadataKey、ControlledShutdownKey、OffsetCommitKey、OffsetFetchKey、ConsumerMetadataKey。

     8、KafkaHealthCheck:broker的健康检查模块。broker在zookeeper上注册目录为/brokers/ids,当broker在线时,对应的id存在,否则不存在。

    9、TopicConfigManager:topic的配置管理模块。在zookeeper上注册目录/config/changes,当数据发送变化时通过回调函数来感知topic的变化。

   10、KafkaController:kafka的集群控制管理模块。由于zookeeper保存了集群中的kafka集群的元数据,KafkaController通过注册不同的回调函数来监听不同元数据的变化,当这些元数据发生变化时,KafkaController就可以感知到这些变化并作出不同的响应,从而达到管理集群的目的。