KafkaZookeeper2-ZookeeperClient
介绍
ZookeeperClient 是 kafka 新写的客户端,它允许用户流水线式(并行)访问 zookeeper。
为什么放弃了 zkClient?
zkClient 是一个第三方的客户端。
它的优点:
- 在session loss和session expire时自动创建新的ZooKeeper实例进行重连。
- 将一次性watcher包装为持久watcher。后者的具体做法是简单的在watcher回调中,重新读取数据的同时再注册相同的watcher实例。[1]
它的缺点:
- zkClient 在处理请求的时候,只能同步的访问处理。当 kafka 的 partition 个数过多的时候,同时请求 zookeeper 就会造成性能的瓶颈。
因为上述的缺点,ZookeeperClient 在访问的时候采用了异步的访问方式,并且采用了批量处理的方式。
如何批量并行访问
1. 获取消息请求队列。
2. 并行处理每个请求。
3. 将所有的请求结果保存在一个列表中返回。
这里需要考虑几种情况?
多线程并发请求,如何等待所有请求处理完成再返回?
CountDownLatch。
假如一个请求队列中的请求太多了,一次性访问 zookeeper 容易过载。怎么办?
控制同时访问 zookeeper 的请求个数。 使用 Semaphore 来实现。
如何异步访问呢?
org.apache.zookeeper
已经为我们实现了。不需要考虑了。
综上,再看 zookeeperClient 的实现:
// 设定同时访问 zookeeper 的最大请求个数
private val inFlightRequests = new Semaphore(maxInFlightRequests)
// 这里 inReadLock(initializationLock) 在某种情况下会产生死锁。4551 修复了这个问题
def handleRequests[Req <: AsyncRequest](requests: Seq[Req]): Seq[Req#Response] = inReadLock(initializationLock) {
if (requests.isEmpty)
Seq.empty
else {
// 设定 CountDownLatch,当前队列的所有请求处理完再返回
val countDownLatch = new CountDownLatch(requests.size)
// 保存处理结果
val responseQueue = new ArrayBlockingQueue[Req#Response](requests.size)
requests.foreach { request =>
// 通过 semaphore 控制多个线程同时访问的最大请求
inFlightRequests.acquire()
try {
// 异步访问
send(request) { response =>
responseQueue.add(response)
inFlightRequests.release()
countDownLatch.countDown()
}
} catch {
case e: Throwable =>
inFlightRequests.release()
throw e
}
}
// 等待所有请求处理完
countDownLatch.await()
// 返回
responseQueue.asScala.toBuffer
}
}
session 如何自动重连?
通过重写 watcher 的 process 函数,在函数中判断当前 zookeeper 对象是否过期,如果过期,就关闭老的,并重新创建一个新的。
// package level visibility for testing only
private[zookeeper] object ZooKeeperClientWatcher extends Watcher {
override def process(event: WatchedEvent): Unit = {
debug(s"Received event: $event")
Option(event.getPath) match {
case None =>
... 发现过期了
} else if (state == KeeperState.Expired) {
inWriteLock(initializationLock) {
info("Session expired.")
// 初始化
initialize()
}
}
... 如果是其他类型的event, 调用相应的handler
}
}
}
private def initialize(): Unit = {
if (!connectionState.isAlive) {
zooKeeper.close()
info(s"Initializing a new session to $connectString.")
// retry forever until ZooKeeper can be instantiated
var connected = false
while (!connected) {
try {
zooKeeper = new ZooKeeper(connectString, sessionTimeoutMs, ZooKeeperClientWatcher)
connected = true
} catch {
case e: Exception =>
info("Error when recreating ZooKeeper, retrying after a short sleep", e)
Thread.sleep(1000)
}
}
}
}
持久 watcher
持久 watcher 就是指在每次请求的时候,都添加相应的 watcher。 kafka 的做法是将所有需要添加 watcher 的路径保存在一个集合中,当请求 zookeeper 的时候, 判断集合中是否包含相应的路径,如果包含就添加 watcher。
1. 保存对应的路径
private val zNodeChangeHandlers = new ConcurrentHashMap[String, ZNodeChangeHandler]().asScala
private val zNodeChildChangeHandlers = new ConcurrentHashMap[String, ZNodeChildChangeHandler]().asScala
2. 添加路径
def registerZNodeChangeHandler(zNodeChangeHandler: ZNodeChangeHandler): Unit = {
zNodeChangeHandlers.put(zNodeChangeHandler.path, zNodeChangeHandler)
}
3. 判断是否存在
private def shouldWatch(request: AsyncRequest): Boolean = request match {
case _: GetChildrenRequest => zNodeChildChangeHandlers.contains(request.path)
case _: ExistsRequest | _: GetDataRequest => zNodeChangeHandlers.contains(request.path)
case _ => throw new IllegalArgumentException(s"Request $request is not watchable")
}
4. 请求的时候做判断
private 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)
}
}
参考
[1] ZooKeeper(四)-- 第三方客户端 ZkClient的使用
KafkaZookeeper2-ZookeeperClient的更多相关文章
- zookeeperclient代码解读
近期一直在忙WebPageTest(下面简称wpt)开源库的改动工作,当中一项工作须要将zookeeper(下面简称zk)集成到wpt里. zk作为分布式系统的同步工具.实现了写的原子性(要么失败.要 ...
- zookeeperclient设置监听
1.目的 zookeeper是一个分布式服务管理框架.zookeeper提供了对client的通知.即在server端的节点有改动或者删除的时候,能够给client进行通知. 2.server端部署 ...
- dubbo连接zookeeper注册中心因为断网导致线程无限等待问题【转】
最近维护的系统切换了网络环境,由联通换成了电信网络,因为某些过滤规则导致系统连不上zookeeper服务器(应用系统机器在深圳,网络为电信线路,zookeeper服务器在北京,网络为联通线路),因为我 ...
- 支持断线重连、永久watcher、递归操作并且能跨平台(.NET Core)的ZooKeeper异步客户端
在公司内部的微服务架构中有使用到了"ZooKeeper",虽然官方有提供了.NET的SDK,但易用性非常的差,且搜遍github.nuget,没有发现一个可以跨平台且易用的组件,所 ...
- Apache curator-client详解
Apache curator框架中curator-client组件可以作为zookeeper client来使用,它提供了zk实例创建/重连机制等,简单便捷.不过直接使用curator-client并 ...
- 基于ZooKeeper的Dubbo注册中心
SOA服务治理 dubbo_zk 服务总线 感兴趣的M我微信:wonter 微信扫描,人人 CTO 大本营 基于SOA架构的TDD测试驱动开发模式 服务治理要先于SOA 简述我的SOA服务治理 从页面 ...
- .NET Core)的ZooKeeper异步客户端
支持断线重连.永久watcher.递归操作并且能跨平台(.NET Core)的ZooKeeper异步客户端 阅读目录 什么是ZooKeeper? 项目介绍 提供的功能 使用说明 FAQ 在公司内部 ...
- 彻底删除Kafka中的topic
1.删除kafka存储目录(server.properties文件log.dirs配置,默认为"/tmp/kafka-logs")相关topic目录 2.Kafka 删除topic ...
- dubbo作为消费者注册过程分析
请支持原创: http://www.cnblogs.com/donlianli/p/3847676.html 作者当前分析的版本为2.5.x.作者在分析的时候,都是带着疑问去查看代码,debug进 ...
- org.apache.hadoop.hbase.TableExistsException: hbase:namespace
Problem is here : https://community.cloudera.com/t5/Storage-Random-Access-HDFS/HMaster-not-starting- ...
随机推荐
- 关于 Visual Studio 中文提示的问题
[转自 https://blog.csdn.net/iloli/article/details/51055299] [转自 http://www.cnblogs.com/hellowin/p/6383 ...
- jQuery分页插件pagination的用法
https://www.zhangxinxu.com/jq/pagination_zh/ 参数: 参数名 描述 参数值 maxentries 总条目数 必选参数,整数 items_per_page 每 ...
- 关于数据未渲染完,要获取document高度问题——ajax全局事件
昨天在做开发时,遇到这样一个问题,当页面刚加载的时候,就要获取document的高度,可是此时页面上所有的ajax请求的数据都还没有渲染到页面上,所以导致得到的document的高度仅仅是页面结构的高 ...
- R dataframe 去除行号
原先的行号是这样的:
- java 读写分离
源码地址:http://git.oschina.net/xiaochangwei 先回答下 1.为啥要读写分离? 大家都知道最初开始,一个项目对应一个数据库,基本是一对一的,但是由于后来用户及数据还有 ...
- 使用css选择器来定位元素
public void CSS(){ driver.get(Constant.baidu_url); //绝对路径 // driver.findElement(By.cssSelector(" ...
- iproute2+tc notes
iproute2+tc notes The iproute2+tc package allows access to the variety of neat new networking featur ...
- css控制单行或者多行文本超出显示省略号
1.单行文本 使用text-overflow:ellipsis属性 text-overflow: clip|ellipsis|string; clip:修剪文本. ellipsis:显示省略符号来代表 ...
- Ubuntu_18.04安装网易云音乐
首先到网易云音乐官网下载网易云音乐,ubuntu版的,安装. 这时候的图标打不开,缺少libcanberra sudo apt install libcanberra-gtk-module 安装完了配 ...
- 中国剩余定理(excrt) 模板
excrt板子题 #include <cmath> #include <cstdio> #include <cstring> #include <algori ...