kazoo
zk是用java开发的,因此sdk对java支持比较好,我们使用的是python语言,借助第三方库kazoo,网站 https://kazoo.readthedocs.io/en/latest/index.html 网站里面有比较详细地介绍kazoo的使用方法和注意事项,我们这里只列举常见的使用方法,具体深入的请前往网站仔细阅读。
安装
安装kazoo比较简单,yum可以使用
yum install python-kazoo
pip可以使用
pip install kazoo
安装成功之后,我们验证一下是否安装可用
[root@localhost ~]# pythonPython 2.7.5 (default, Jul 13 2018, 13:06:57) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux2Type "help", "copyright", "credits" or "license" for more information.>>> from kazoo.client import KazooClient>>> #能够import的证明安装成功可用了
CRUD例子
我们先写一个最简单的节点CRUD例子,kazoo这个库它内部会开工作线程执行相关连接和指令操作,不会阻塞主线程,还有在kazoo线程再去执行zk的指令操作会卡死整个程序,这个是需要注意的。
import signal
import sys
import time
import logging
from kazoo.client import KazooClient
from kazoo.client import KazooState
#用于捕获ctrl+c退出程序
is_exit = False
#记录当前kazoo连接状态
cur_state = None
def sigint_handler(signum, frame):
global is_exit
is_exit = True
#回调通知kazoo当前状态,并记录在全局变量 cur_state
def my_listener(state):
# KazooState.LOST
# KazooState.CONNECTED
# KazooState.SUSPENDED
global cur_state
print state
cur_state = state
#相关zk的CRUD指令测试
def do_something():
#先检查一下是否存在节点 /my/favorite/node
ret = zk.exists("/my/favorite/node")
print ret
if ret:
#如果节点则删除
zk.delete("/my/favorite/node", recursive=True)
return
#递归创建路径
zk.ensure_path("/my/favorite")
#创建节点并设置数据
zk.create("/my/favorite/node", b"a value")
#获取节点信息
data, stat = zk.get("/my/favorite/node")
print("Version: %s, data: %s" % (stat.version, data.decode("utf-8")))
#获取子节点信息
children = zk.get_children("/my/favorite")
print("There are %s children with names %s" % (len(children), children))
if __name__ == "__main__":
#ctrl+c
signal.signal(signal.SIGINT, sigint_handler)
signal.signal(signal.SIGHUP, sigint_handler)
signal.signal(signal.SIGTERM, sigint_handler)
#参考官方用法不报错
logging.basicConfig()
#实例一个kazoo对象
zk = KazooClient(hosts='127.0.0.1:2181')
#监听kazoo连接状态回调
zk.add_listener(my_listener)
#开始
zk.start()
while not is_exit:
time.sleep(1)
#只有当前状态是连接才去做相关CRUD测试
#这里不太严谨因为多线程情况下又可能连接突然断掉了还没来得及
#更新状态然后就去做CRUD操作了,这里仅作为演示代码不考虑复杂情况
if cur_state and cur_state == KazooState.CONNECTED:
do_something()
break
#停止kazoo实例
zk.stop()
监听
除了CRUD常用操作以外,还有一个非常实用的功能就是监听节点(可以是节点的添加、删除、节点的数据更新)。kazoo提供了2种监听节点的方法,第一种是比较简单的,如下面官方提供的代码例子:
def my_func(event):
# check to see what the children are now
# Call my_func when the children change
children = zk.get_children("/my/favorite/node", watch=my_func)
这种监听方法,当对应节点触发了,只会通知回调一次,如果需要继续监听需要再手动设置多次监听函数。下面介绍另外一种监听方法,只需要设定一次,每次有事件都会通知到回调函数而且通知类型数据比较丰富。下面列的是官方的例子代码片段,使用了python的装饰器。
@zk.ChildrenWatch("/my/favorite/node")
def watch_children(children):
print("Children are now: %s" % children)
# Above function called immediately, and from then on
@zk.DataWatch("/my/favorite")
def watch_node(data, stat):
print("Version: %s, data: %s" % (stat.version, data.decode("utf-8")))
一个完整的监听例子代码
import signal
import sys
import time
import logging
from kazoo.client import KazooClient
from kazoo.client import KazooState
is_exit = False
cur_state = None
def sigint_handler(signum, frame):
global is_exit
is_exit = True
def my_listener(state):
global cur_state
print state
cur_state = state
def set_watch():
#监听 /my/favorite 下的节点事件
#可以先做上面的测试例子会创建好 /my/favorite 节点或者手动去zk创建
@zk.ChildrenWatch("/my/favorite")
def watch_children(children):
print("Children are now: %s" % children)
# Above function called immediately, and from then on
#监听指定节点 /my/favorite/node 事件
@zk.DataWatch("/my/favorite/node")
def watch_node(data, stat):
print("Version: %s, data: %s" % (stat.version, data.decode("utf-8")))
print repr(stat)
print repr(data)
if __name__ == "__main__":
signal.signal(signal.SIGINT, sigint_handler)
signal.signal(signal.SIGHUP, sigint_handler)
signal.signal(signal.SIGTERM, sigint_handler)
logging.basicConfig()
zk = KazooClient(hosts='127.0.0.1:2181')
zk.add_listener(my_listener)
zk.start()
is_set_watch = False
while not is_exit:
time.sleep(1)
if cur_state and cur_state == KazooState.CONNECTED:
#当client建立连接后再设置监听回调
if not is_set_watch:
is_set_watch = True
set_watch()
else:
continue
zk.stop()
测试
先运行测试程序,然后再开一个新的ssh中断使用zkCli.sh连接zk,执行以下测试指令
#创建一个测试节点
create /my/favorite/test 'test'
#删除测试节点
delete /my/favorite/test
#设置节点数据
set /my/favorite/node '123'
测试程序先后输出如下
#当创建 test 测试节点的时候,函数回调输出当前节点列表,发现新增节点test
Children are now: [u'node', u'test']
#当删除 test 测试节点的时候,函数回调输出当前节点列表,已经没有节点test
Children are now: [u'node']
#当设置节点node数据时,函数回调输出相关数据信息
Version: 26, data: 123
ZnodeStat(czxid=114, mzxid=204, ctime=1538012242884, mtime=1538035424029, version=26, cversion=0, aversion=0, ephemeralOwner=0, dataLength=3, numChildren=0, pzxid=114)
'123'