Kafka源码分析(1)

来源:互联网 发布:maya2015软件补丁更新 编辑:程序博客网 时间:2024/05/01 06:37

           选择Kafka0.8.2.2版本进行说明,0.8以后基本都是这个架构。因为0.9以后版本的设计有比较大的变化,因此不适用于0.9以后版本代码。

           本文假设读者对Kafka的基本概念已有了解。


一启动

1、入口

           Kafka类中的main方法是整个Kafka的入口。首先是解析命令行参数,并封装为一个KafkaConfig对象。接着用该参数创建一个KafkaServerStartable对象并启动,同时注册一个监听事件用于监测用户输入的ctrl-c,也就是说只有用户ctrl-c或抛出异常时,Kafka进程才会终止,这部分代码简单。

2、启动KafkaServer

           KafkaServerStartable只是KafkaServer的封装,实际启动动作都在KafkaServer内。startup()方法内有以下动作:

           启动scheduler,scheduler的作用是调度Kafka内的所有线程,包括新建调度,终止调度,调度任务等,这里会执行新建调度过程;

           连接zookeeper服务器,如果Kafka的根节点存在,则注册到zk并成为client;

           启动LogManager,这个是用来打日志的,不细说;

           启动SocketServer,这个很重要,是用来管理Kafka集群内的socket连接的。kafka.network. SocketServer代码的头部说得很清楚,SocketServer是基于NIO实现的socket服务,线程模型为:1个Acceptor线程用于接受新的连接,N个Processor线程每个都会通过读请求从socket读取数据,M个Handler线程处理当前等待的Processor线程发起的读请求并给出响应。其中N的参数在创建SocketServer时传入,并马上创建N个Processor线程和1个Acceptor线程。Handler线程在哪创建?)

for(i <- 0 until numProcessorThreads) {      processors(i) = new Processor(i,                                     time,                                     maxRequestSize,                                     aggregateIdleMeter,                                    newMeter("IdlePercent", "percent", TimeUnit.NANOSECONDS, Map("networkProcessor" -> i.toString)),                                    numProcessorThreads,                                     requestChannel,                                    quotas,                                    connectionsMaxIdleMs)      Utils.newThread("kafka-network-thread-%d-%d".format(port, i), processors(i), false).start()    }………………this.acceptor = new Acceptor(host, port, processors, sendBufferSize, recvBufferSize, quotas)Utils.newThread("kafka-socket-acceptor", acceptor, false).start()acceptor.awaitStartupinfo("Started")

           创建ReplicaManager,这个对象非常重要,每个broker就靠他来使自己成为ISR(即in-syncReplica,与Leader同步的Replica列表)的一员,包括处理Replica、读取数据、成为Leader或Follower等。这里只是new该对象。(后面详细讲)


           创建offsetManager,这个也比较重要,是用来管理每个group/topic/partition组合消费到哪个offset的。Kafka有两种消息消费方式,一种是顺序消费,一种是乱序消费(即通过指定该offset来实现),这里不展开讲。

           创建KafkaController,它涉及到Kafka选举Leader的问题,0.8以后的选举方式是,在所有broker中选出一个controller,所有Partition的Leader选举都由controller决定。controller会将Leader的改变直接通过RPC的方式(比ZooKeeperQueue的方式更高效)通知需为为此作为响应的Broker。同时controller也负责增删Topic以及Replica的重新分配。此处初始化该KafkaController对象。

           接下去就是准备开始响应请求了。Kafka在这里实现得比较严谨,用一个KafkaApis类包装了各种请求类型的响应,通过requestId来区分调用哪个。KafkaRequestHandlerPool是一个线程池,用于处理传入的KafkaApis对象。

           创建TopicConfigManager对象,用户处理topicconfig的变更。topic config在zk上的存储路径是/brokers/topics/<topic_name>/config,但所有topicconfig变更的通知会先存放到/brokers/config_changes,以便减小扫描量。

           最后,启动过程会创建一个KafkaHealthcheck对象,用于向其他broker通知自己的状态已经活了。至此所有启动过程结束。


           下面几节分重点模块和功能说明各部分的代码逻辑。Kafka broker的总体架构如下图:


0 0