创建ZooKeeper客户端
其中CanBeReadOnly的含义蛮有意思:在ZooKeeper集群中,如果一个机器出故障了,与半数以上机器失去联系,按理说是不能提供服务了。在特殊情况下(几乎不写的情况),还是希望它提供读服务。
object MyWatcher : Watcher{
override fun process(event: WatchedEvent?) {
when (event?.type){
Watcher.Event.EventType.NodeCreated
-> println("path create : ${event.path}")
Watcher.Event.EventType.NodeChildrenChanged
-> println("child changed in : ${event.path}")
else -> println("UnKnown event")
}
}
}
object ZKManager{
//服务器列表
val hostPort = "localhost:2181,localhost:2182,localhost:2183"
//心跳检测超时时长
val sessionTime = 5000
//事件监听器
val watcher = MyWatcher
//是否只读,默认false
val canBeReadOnly = false
//会话重用ID
var sessionId: Long? = null
//会话重用密码
var sessionPWD: ByteArray? = null
var zk: ZooKeeper? = null
fun getZooKeeper(Id: Long? = sessionId,
PWD: ByteArray? = sessionPWD,
newSession: Boolean = false,
anotherSessin: Boolean = false): ZooKeeper? {
if (anotherSessin){
return ZooKeeper(hostPort, sessionTime, watcher)
}
if (sessionId != null && sessionPWD != null){
zk?.close()
zk = ZooKeeper(hostPort, sessionTime, watcher, Id!!,PWD)
}
if (newSession || (zk == null)){
zk?.close()
zk = ZooKeeper(hostPort, sessionTime, watcher)
}
return zk
}
fun saveSession(){
sessionId = zk?.sessionId
sessionPWD = zk?.sessionPasswd
}
}
fun main(args: Array<String>){
val zk = ZKManager.getZooKeeper()
println("The State is ${zk?.state} and the sesion is ${zk?.sessionId}")
println("id: ${zk?.sessionId} => ${zk?.sessionPasswd}")
val otherZk = ZKManager.getZooKeeper(anotherSessin = true)
println("The State is ${otherZk?.state} and the sesion is ${otherZk?.sessionId}")
println("id: ${otherZk?.sessionId} => ${otherZk?.sessionPasswd}")
ZKManager.saveSession()
val reloadZk = ZKManager.getZooKeeper()
println("The State is ${reloadZk?.state} and the sesion is ${reloadZk?.sessionId}")
println("id: ${reloadZk?.sessionId} => ${reloadZk?.sessionPasswd}")
zk?.close()
otherZk?.close()
reloadZk?.close()
}
/*
The State is CONNECTING and the sesion is 0
id: 0 => [B@377dca04
The State is CONNECTING and the sesion is 0
id: 0 => [B@728938a9
UnKnown event
UnKnown event
The State is CONNECTING and the sesion is 0
id: 0 => [B@377dca04
UnKnown event
*/
创建节点
fun ZKManager.createMaster(){
val path = "/master"
val data = "content".toByteArray()
//权限
val acl = ZooDefs.Ids.OPEN_ACL_UNSAFE
//临时节点
val mode = CreateMode.EPHEMERAL
//可以为null,保存上下文信息,可以为一个Session
val context = "I am context"
//回调函数,rc是状态码,path是上面传进去的path
//ctx是上面传入的context, name是成功返回path,否则null
val callback = { rc: Int, path: String?, ctx: Any?, name: String? ->
println("Create path result: [ $rc , $path , real path name:$name ]")
}
//这步创建一下客户端,有则直接返回
getZooKeeper()
this.zk?.create(path,data,acl,mode,callback,context)
}
fun main(args: Array<String>){
ZKManager.createMaster()
ZKManager.createMaster()
ZKManager.createMaster()
Thread.sleep(10000)
}
/*
Create path result: [ 0 , /master , real path name:/master ]
Create path result: [ -110 , /master , real path name:null ]
Create path result: [ -110 , /master , real path name:null ]
*/
删除节点
只允许删除没有子节点的节点,version必须和当前版本一致才能删除成功,如果是-1则和任何版本都一致
获取子节点
前4个方法使用ZooKeeper创建时候的Watcher.后4个使用自定义的Watcher
//更改,当NodeChildrenChanged时,列出所有子节点
object MyWatcher : Watcher{
override fun process(event: WatchedEvent?) {
when (event?.type){
Watcher.Event.EventType.NodeCreated
-> println("path create : ${event.path}")
Watcher.Event.EventType.NodeChildrenChanged
-> println("get child: ${ZKManager.zk?.getChildren(event.path,true)}")
else -> println("UnKnown event")
}
}
}
fun ZKManager.addChildren(){
val path = "/master/slave"
val data = "".toByteArray()
val acl = ZooDefs.Ids.OPEN_ACL_UNSAFE
val mode = CreateMode.EPHEMERAL_SEQUENTIAL
//在/master上添加监控
val children= this.zk?.getChildren("/master",true)
println(children)
for (i in 1..5){
this.zk?.create(path,data,acl,mode)
}
}
fun main(args: Array<String>){
ZKManager.createMaster()
ZKManager.addChildren()
Thread.sleep(10000)
}
/*
[]
Create path result: [ -110 , /master , real path name:null ]
get child: [slave0000000011]
get child: [slave0000000011, slave0000000012]
get child: [slave0000000011, slave0000000013, slave0000000012]
get child: [slave0000000011, slave0000000013, slave0000000012, slave0000000014]
get child: [slave0000000011, slave0000000013, slave0000000012, slave0000000015, slave0000000014]
*/
获取数据
version: 和上面一样,CAS的原理
//增加NodeDataChanged
object MyWatcher : Watcher{
override fun process(event: WatchedEvent?) {
when (event?.type){
Watcher.Event.EventType.NodeCreated
-> println("path create : ${event.path}")
Watcher.Event.EventType.NodeChildrenChanged
-> println("get child: ${ZKManager.zk?.getChildren(event.path,true)}")
Watcher.Event.EventType.NodeDataChanged
-> println("data in ${event.path} changed to : ${ZKManager.getData(event.path)}")
else -> println("UnKnown event")
}
}
}
fun ZKManager.getData(path: String): String{
val path = path
val watch = true
val stat = Stat()
val data: ByteArray = this.zk?.getData(path,watch,stat)!!
return String(data)
}
fun ZKManager.setData(path: String, data: String){
val path = path
val d = data.toByteArray()
zk?.setData(path, d, -1)
}
fun main(args: Array<String>){
ZKManager.getZooKeeper()
val d1 = ZKManager.getData("/master")
println(d1)
val executor = Executors.newFixedThreadPool(5)
for (i in 1..5){
executor.execute { ZKManager.setData("/master","content${i}") }
//这里只是为了注册Watcher
val d = ZKManager.getData("/master")
}
executor.shutdown()
Thread.sleep(10000)
}
/*
UnKnown event
content5
data in /master changed to : content3
data in /master changed to : content4
data in /master changed to : content5
data in /master changed to : content5
*/
Exist()
这里的watcher会监控创建,删除,更新三种事件
权限控制
有时一个ZooKeeper集群会为很多不同的应用提供服务,这个应用不需要共享数据,因此在不同应用之间有权限问题。
schema:控制模式:world,auth,digest,ip和super
auth:具体的权限信息
val zk1 = ZKManager.getZooKeeper(anotherSessin = true)
//声明是只有创建者有权限
val acl = ZooDefs.Ids.CREATOR_ALL_ACL
val mode = CreateMode.EPHEMERAL
//增加权限内容
zk1?.addAuthInfo("digest","foo:true".toByteArray())
zk1?.create("/master","".toByteArray(),acl,mode)
val anotherZK = ZKManager.getZooKeeper(anotherSessin = true)
val data = anotherZK?.getData("/master",false,Stat())
println(String(data!!))
Thread.sleep(20000)
/*
UnKnown event
UnKnown event
Exception in thread "main" org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /master
*/
但只要加上权限就可以访问了
anotherZK?.addAuthInfo("digest","foo:true".toByteArray())
对删除节点比较特殊,比如创建了/master和/master/one。没有权限则不能删除/master/one
//创建节点/master,/master/1
val zk1 = ZKManager.getZooKeeper(anotherSessin = true)
val acl = ZooDefs.Ids.CREATOR_ALL_ACL
val mode = CreateMode.PERSISTENT
zk1?.addAuthInfo("digest","foo:true".toByteArray())
zk1?.create("/master","content".toByteArray(),acl,mode)
zk1?.create("/master/1","one".toByteArray(),acl,mode)
Thread.sleep(500)
val zk2 = ZKManager.getZooKeeper(anotherSessin = true)
zk2?.addAuthInfo("digest","foo:true".toByteArray())
zk2?.delete("/master/1",-1)
Thread.sleep(500)
val zk3 = ZKManager.getZooKeeper(anotherSessin = true)
zk3?.delete("/master",-1)