kafka启动第一步是生成zkclient,然后连接zk服务器,创建通用节点及注册brokerinfo相关操作! 我们就先从zookeeper相关操作类开始!
kafka操作zookeeper得主要类如下图:
ZookeeperClient: 流水线请求的ZooKeeper客户端。
KafkaZkClient: 基于ZookeeperClient构建的特定于kafka操作的客户端!
AdminZkClient: 提供与管理员交互的管理相关方法!对KafkaZkClient的封装!
ZkData: 在ZooKeeper节点中存储的数据的对象
ZKSecurityMigratorUtils: Zk安全迁移器工具。
1. ZookeeperClient
ZookeeperClient 是kafka操作zookeeper的基础类,所有操作都是基于对它的二次封装,主要方法有:
1.1 构造函数,创建ZookeeperClient对象
this.logIdent = name match {
case Some(n) => s"[ZooKeeperClient $n] "
case _ => "[ZooKeeperClient] "
}
private val initializationLock = new ReentrantReadWriteLock()
private val isConnectedOrExpiredLock = new ReentrantLock()
private val isConnectedOrExpiredCondition = isConnectedOrExpiredLock.newCondition()
private val zNodeChangeHandlers = new ConcurrentHashMap[String, ZNodeChangeHandler]().asScala
private val zNodeChildChangeHandlers = new ConcurrentHashMap[String, ZNodeChildChangeHandler]().asScala
private val inFlightRequests = new Semaphore(maxInFlightRequests)
private val stateChangeHandlers = new ConcurrentHashMap[String, StateChangeHandler]().asScala
private[zookeeper] val expiryScheduler = new KafkaScheduler(threads = 1, "zk-session-expiry-handler")
private val metricNames = Set[String]()
// The state map has to be created before creating ZooKeeper since it's needed in the ZooKeeper callback.
private val stateToMeterMap = {
import KeeperState._
val stateToEventTypeMap = Map(
Disconnected -> "Disconnects",
SyncConnected -> "SyncConnects",
AuthFailed -> "AuthFailures",
ConnectedReadOnly -> "ReadOnlyConnects",
SaslAuthenticated -> "SaslAuthentications",
Expired -> "Expires"
)
stateToEventTypeMap.map { case (state, eventType) =>
val name = s"ZooKeeper${eventType}PerSec"
metricNames += name
state -> newMeter(name, eventType.toLowerCase(Locale.ROOT), TimeUnit.SECONDS)
}
}
info(s"Initializing a new session to $connectString.")
// Fail-fast if there's an error during construction (so don't call initialize, which retries forever)
@volatile private var zooKeeper = new ZooKeeper(connectString, sessionTimeoutMs, ZooKeeperClientWatcher)
newGauge("SessionState", new Gauge[String] {
override def value: String = Option(connectionState.toString).getOrElse("DISCONNECTED")
})
metricNames += "SessionState"
expiryScheduler.startup()
try waitUntilConnected(connectionTimeoutMs, TimeUnit.MILLISECONDS)
catch {
case e: Throwable =>
close()
throw e
}
1.2. zookeeper 0p操作封装
sealed trait ZkOp {
def toZookeeperOp: Op
}
case class CreateOp(path: String, data: Array[Byte], acl: Seq[ACL], createMode: CreateMode) extends ZkOp {
override def toZookeeperOp: Op = Op.create(path, data, acl.asJava, createMode)
}
case class DeleteOp(path: String, version: Int) extends ZkOp {
override def toZookeeperOp: Op = Op.delete(path, version)
}
case class SetDataOp(path: String, data: Array[Byte], version: Int) extends ZkOp {
override def toZookeeperOp: Op = Op.setData(path, data, version)
}
case class CheckOp(path: String, version: Int) extends ZkOp {
override def toZookeeperOp: Op = Op.check(path, version)
}
case class ZkOpResult(zkOp: ZkOp, rawOpResult: OpResult)
1.3 kafka请求zookeeper
sealed trait AsyncRequest {
/**
* This type member allows us to define methods that take requests and return responses with the correct types.
* See ``ZooKeeperClient.handleRequests`` for example.
*/
type Response <: AsyncResponse
def path: String
def ctx: Option[Any]
}
sealed abstract class AsyncResponse {
def resultCode: Code
def path: String
def ctx: Option[Any]
/** Return None if the result code is OK and KeeperException otherwise. */
def resultException: Option[KeeperException] =
if (resultCode == Code.OK) None else Some(KeeperException.create(resultCode, path))
/**
* Throw KeeperException if the result code is not OK.
*/
def maybeThrow(): Unit = {
if (resultCode != Code.OK)
throw KeeperException.create(resultCode, path)
}
def metadata: ResponseMetadata
}
/**
* Send a request and wait for its response. See handle(Seq[AsyncRequest]) for details.
*
* @param request a single request to send and wait on.
* @return an instance of the response with the specific type (e.g. CreateRequest -> CreateResponse).
*/
def handleRequest[Req <: AsyncRequest](request: Req): Req#Response = {
handleRequests(Seq(request)).head
}
/**
* Send a pipelined sequence of requests and wait for all of their responses.
*
* The watch flag on each outgoing request will be set if we've already registered a handler for the
* path associated with the request.
*
* @param requests a sequence of requests to send and wait on.
* @return the responses for the requests. If all requests have the same type, the responses will have the respective
* response type (e.g. Seq[CreateRequest] -> Seq[CreateResponse]). Otherwise, the most specific common supertype
* will be used (e.g. Seq[AsyncRequest] -> Seq[AsyncResponse]).
*/
def handleRequests[Req <: AsyncRequest](requests: Seq[Req]): Seq[Req#Response] = {
if (requests.isEmpty)
Seq.empty
else {
val countDownLatch = new CountDownLatch(requests.size)
val responseQueue = new ArrayBlockingQueue[Req#Response](requests.size)
requests.foreach { request =>
inFlightRequests.acquire()
try {
inReadLock(initializationLock) {
send(request) { response =>
responseQueue.add(response)
inFlightRequests.release()
countDownLatch.countDown()
}
}
} catch {
case e: Throwable =>
inFlightRequests.release()
throw e
}
}
countDownLatch.await()
responseQueue.asScala.toBuffer
}
}
// Visibility to override for testing
private[zookeeper] def send[Req <: AsyncRequest](request: Req)(processResponse: Req#Response => Unit): Unit = {
// Safe to cast as we always create a response of the right type
def callback(response: AsyncResponse): Unit = processResponse(response.asInstanceOf[Req#Response])
def responseMetadata(sendTimeMs: Long) = new ResponseMetadata(sendTimeMs, receivedTimeMs = time.hiResClockMs())
val sendTimeMs = time.hiResClockMs()
request match {
case ExistsRequest(path, ctx) =>
zooKeeper.exists(path, shouldWatch(request), new StatCallback {
override def processResult(rc: Int, path: String, ctx: Any, stat: Stat): Unit =
callback(ExistsResponse(Code.get(rc), path, Option(ctx), stat, responseMetadata(sendTimeMs)))
}, ctx.orNull)
case GetDataRequest(path, ctx) =>
zooKeeper.getData(path, shouldWatch(request), new DataCallback {
override def processResult(rc: Int, path: String, ctx: Any, data: Array[Byte], stat: Stat): Unit =
callback(GetDataResponse(Code.get(rc), path, Option(ctx), data, stat, responseMetadata(sendTimeMs)))
}, ctx.orNull)
case GetChildrenRequest(path, ctx) =>
zooKeeper.getChildren(path, shouldWatch(request), new Children2Callback {
override def processResult(rc: Int, path: String, ctx: Any, children: java.util.List[String], stat: Stat): Unit =
callback(GetChildrenResponse(Code.get(rc), path, Option(ctx),
Option(children).map(_.asScala).getOrElse(Seq.empty), stat, responseMetadata(sendTimeMs)))
}, ctx.orNull)
case CreateRequest(path, data, acl, createMode, ctx) =>
zooKeeper.create(path, data, acl.asJava, createMode, new StringCallback {
override def processResult(rc: Int, path: String, ctx: Any, name: String): Unit =
callback(CreateResponse(Code.get(rc), path, Option(ctx), name, responseMetadata(sendTimeMs)))
}, ctx.orNull)
case SetDataRequest(path, data, version, ctx) =>
zooKeeper.setData(path, data, version, new StatCallback {
override def processResult(rc: Int, path: String, ctx: Any, stat: Stat): Unit =
callback(SetDataResponse(Code.get(rc), path, Option(ctx), stat, responseMetadata(sendTimeMs)))
}, ctx.orNull)
case DeleteRequest(path, version, ctx) =>
zooKeeper.delete(path, version, new VoidCallback {
override def processResult(rc: Int, path: String, ctx: Any): Unit =
callback(DeleteResponse(Code.get(rc), path, Option(ctx), responseMetadata(sendTimeMs)))
}, ctx.orNull)
case GetAclRequest(path, ctx) =>
zooKeeper.getACL(path, null, new ACLCallback {
override def processResult(rc: Int, path: String, ctx: Any, acl: java.util.List[ACL], stat: Stat): Unit = {
callback(GetAclResponse(Code.get(rc), path, Option(ctx), Option(acl).map(_.asScala).getOrElse(Seq.empty),
stat, responseMetadata(sendTimeMs)))
}}, ctx.orNull)
case SetAclRequest(path, acl, version, ctx) =>
zooKeeper.setACL(path, acl.asJava, version, new StatCallback {
override def processResult(rc: Int, path: String, ctx: Any, stat: Stat): Unit =
callback(SetAclResponse(Code.get(rc), path, Option(ctx), stat, responseMetadata(sendTimeMs)))
}, ctx.orNull)
case MultiRequest(zkOps, ctx) =>
zooKeeper.multi(zkOps.map(_.toZookeeperOp).asJava, new MultiCallback {
override def processResult(rc: Int, path: String, ctx: Any, opResults: util.List[OpResult]): Unit = {
callback(MultiResponse(Code.get(rc), path, Option(ctx),
if (opResults == null)
null
else
zkOps.zip(opResults.asScala) map { case (zkOp, result) => ZkOpResult(zkOp, result) },
responseMetadata(sendTimeMs)))
}
}, ctx.orNull)
}
}
1.3 添加handler
trait StateChangeHandler {
val name: String
def beforeInitializingSession(): Unit = {}
def afterInitializingSession(): Unit = {}
def onAuthFailure(): Unit = {}
}
trait ZNodeChangeHandler {
val path: String
def handleCreation(): Unit = {}
def handleDeletion(): Unit = {}
def handleDataChange(): Unit = {}
}
trait ZNodeChildChangeHandler {
val path: String
def handleChildChange(): Unit = {}
}
2. KafkaClient:
kafkaClient 类主要提供kafka操作zookeeper。方法比较简单,可以直接看对应的类!
3. ZkData
在ZooKeeper节点中存储的数据的对象
4. kafka注册zookeeper流程:
4.1 //创建client
_zkClient = createZkClient(config.zkConnect, secureAclsEnabled)
方法调用栈如下:
startup():79, KafkaScheduler {kafka.utils}, KafkaScheduler.scala
<init>(String, int, int, int, Time, String, String, Option):111, ZooKeeperClient {kafka.zookeeper}, ZooKeeperClient.scala
apply(String, boolean, int, int, int, Time, String, String, Option):1826, KafkaZkClient$ {kafka.zk}, KafkaZkClient.scala
createZkClient$1(String, boolean, Time):364, KafkaServer {kafka.server}, KafkaServer.scala
initZkClient(Time):387, KafkaServer {kafka.server}, KafkaServer.scala
startup():206, KafkaServer {kafka.server}, KafkaServer.scala
startup():38, KafkaServerStartable {kafka.server}, KafkaServerStartable.scala
main(String[]):75, Kafka$ {kafka}, Kafka.scala
main(String[]):-1, Kafka {kafka}, Kafka.scala
最后创建一个线程池:
"SensorExpiryThread"@3,963
4.2 //初始化路劲信息:
_zkClient.createTopLevelPaths()
//ConsumerPathZNode.path, // old consumer path "/consumers"
//BrokerIdsZNode.path, "/brokers/ids"
//TopicsZNode.path, "/brokers/topics"
//ConfigEntityChangeNotificationZNode.path, "/config/changes"
//DeleteTopicsZNode.path, "/admin/delete_topics"
//BrokerSequenceIdZNode.path, "/brokers/seqid"
//IsrChangeNotificationZNode.path, "/isr_change_notification"
//ProducerIdBlockZNode.path, "/latest_producer_id_block"
//LogDirEventNotificationZNode.path "log_dir_event_notification"
_zkClient.createTopLevelPaths()
4.3 初始化clusterid
_clusterId = getOrGenerateClusterId(zkClient)
4.4 向zookeeper注册broker 动态配置属性
config.dynamicConfig.initialize(zkClient)
4.5