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- ...
随机推荐
- Windows下Word.exe在哪?
在这里: C:\Program Files\Microsoft Office\root\Office16
- Python笔记(七)
# -*-coding:utf-8-*- # Python 文件I/O # 打印到屏幕 #print 1234567 # 读取屏幕输入 #input_str=raw_input("Pleas ...
- tomcat开启https服务
一.创建证书 证书是单点登录认证系统中很重要的一把钥匙,客户端于服务器的交互安全靠的就是证书:本教程由于是演示所以就自己用JDK自带的keytool工具生成证书:如果以后真正在产品环境中使用肯定要去证 ...
- 20个非常有用的Java程序片段--转
原文地址:http://geek.csdn.net/news/detail/236591 下面是20个非常有用的Java程序片段,希望能对你有用. 1. 字符串有整型的相互转换 String a = ...
- adplus 抓取dump
工具所在路径 C:\Program Files\Windows Kits\10\Debuggers\x64 cmd窗口切换目录倒adplus所在路径下,输入抓取命令.adplus -hang -p ...
- NGUI 使用Grid自动排列UI
1,NGUI->Create Grid 2,把需要排列的UI放到Grid下边,对Grid进行参数设置
- C++_String_类字符串操作(转)
从百度文库找的,挺详细的,跟大家分享一下. 标红的是我觉得用的比较多,并且大家不太熟悉的. string类的构造函数: string(const char *s); //用c字符串s初始化 s ...
- ZBrush中如何对模型进行减面操作
Decimation Master是ZBrush 4R8自带的一个插件.中文名叫减面大师.其功能非常强大,也非常的方便,可以帮助我们提高效率,减少电脑资源损耗.作为一名3D美术师是必须掌握的一个技术. ...
- HDU 1756 Cupid's Arrow( 判断点在多边形的内外 )
链接:传送门 思路:判断每支箭是否在多边形内,计算几何点定位中水题,不清楚下面的代码能不能适用于给定点的顺序不确定( 既不是顺时针又不是逆时针 ) /************************* ...
- JS生成数字加减乘法验证码
给大家分享一个简单的js验证码生成代码 PS:该代码依赖Jquery1.4版本以上 传入元素 如productionVerificationCode(#\(("a")) 反回验证码 ...