ZooKeeper(4)Java API

创建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)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值