官网:https://zookeeper.apache.org/
godoc文档:https://godoc.org/github.com/samuel/go-zookeeper/zk#Conn.GetW
参考文章:https://www.cnblogs.com/zhichaoma/p/12640064.html
在上篇博文中说了kafka,它依赖于zookeeper,尽管在最新版中,kafka尽量在弱化zookeeper,但还是无法脱离zookeeper,可见zookeeper的强大。
ZooKeeper是一项集中式服务,用于维护配置信息,命名,提供分布式同步和提供组服务。所有这些类型的服务都以某种形式被分布式应用程序使用。每次实施它们时,都会进行很多工作来修复不可避免的错误和竞争条件。由于难以实现这类服务,因此应用程序最初通常会跳过它们,这会使它们在存在更改的情况下变得脆弱并且难以管理。即使部署正确,这些服务的不同实现也会导致管理复杂。
依然是docker安装,方法见上篇博文:https://blog.csdn.net/qq_25490573/article/details/107229554
比较尴尬的一点是,zk只出了java和c的包,golang需要依赖第三方包。
文档地址:https://godoc.org/github.com/samuel/go-zookeeper/zk
go get github.com/samuel/go-zookeeper
type ZKManage struct {
Conn * zk.Conn
Event <-chan zk.Event
}
func NewZKManage(addr []string)*ZKManage{
conn,eventchan,err := zk.Connect(addr,time.Second*5)
if err!=nil{
panic(err)
}
zkm := new(ZKManage)
zkm.Conn = conn
zkm.Event = eventchan
return zkm
}
func(z *ZKManage)Insert(path,value string)error{
acls := zk.WorldACL(zk.PermAll)
// 0:永久,除非手动删除
// zk.FlagEphemeral = 1:短暂,session断开则该节点也被删除
// zk.FlagSequence = 2:会自动在节点后面添加序号
// 3:Ephemeral和Sequence,即,短暂且自动添加序号
res,err := z.Conn.Create(path,[]byte(value),0,acls)
if err!=nil{
return err
}
fmt.Println("Insert:",res)
return nil
}
func(z *ZKManage)Delete(path string)error{
_,stat,_ := z.Conn.Get(path)
// 删改与增不同在于其函数中的version参数,其中version是用于 CAS支持
// 可以通过此种方式保证原子性
return z.Conn.Delete(path,stat.Version)
}
func(z *ZKManage)Update(path,value string)error{
_,stat,_ := z.Conn.Get(path)
_, err :=z.Conn.Set(path,[]byte(value),stat.Version)
return err
}
func(z *ZKManage)Select(path string)[]byte{
data,_,_ := z.Conn.Get(path)
return data
}
func InitZookeeper()(){
zkm := NewZKManage([]string{"192.168.254.172:2181"})
defer zkm.Conn.Close()
path := "/test"
if err := zkm.Insert(path,"this is a test data");err !=nil{
fmt.Println(err)
return
}else {
fmt.Println("insert success")
}
fmt.Println("select:",string(zkm.Select(path)))
if err := zkm.Update(path,"this is a update data");err !=nil{
fmt.Println(err)
return
}else {
fmt.Println("update success")
}
if err := zkm.Delete(path);err!=nil{
fmt.Println(err)
}else {
fmt.Println("delete success")
}
}
首先声明一个回调函数
func CallBlack(event zk.Event){
fmt.Println("-----------event call black--------------")
fmt.Println("path: ", event.Path)
fmt.Println("type: ", event.Type.String())
fmt.Println("state: ", event.State.String())
fmt.Println("-----------------------------------------")
}
然后修改NewZKManage函数
func NewZKManage(addr []string,path string)*ZKManage{
conn,eventchan,err := zk.Connect(addr,time.Second*5,zk.WithEventCallback(CallBlack))
if err!=nil{
panic(err)
}
//ExistsW 一次触发后不再触发
_,_,_,err = conn.ExistsW(path)
if err!=nil{
panic(err)
}
zkm := new(ZKManage)
zkm.Conn = conn
zkm.Event = eventchan
return zkm
}
声明全局监听函数
//全局监听
func WatchZkEvent(e <-chan zk.Event) {
event := <-e
fmt.Println("-----------------全局监听-----------------")
fmt.Println("path: ", event.Path)
fmt.Println("type: ", event.Type.String())
fmt.Println("state: ", event.State.String())
fmt.Println("-----------------------------------------")
}
修改创建函数,在连接时去掉回调函数设置,全局监听也只触发一次
func NewZKManage(addr []string,path string)*ZKManage{
conn,eventchan,err := zk.Connect(addr,time.Second*5)
if err!=nil{
panic(err)
}
//ExistsW 一次触发后不再触发
_,_,event,err := conn.ExistsW(path)
if err!=nil{
panic(err)
}
go WatchZkEvent(event)
zkm := new(ZKManage)
zkm.Conn = conn
zkm.Event = eventchan
return zkm
}
注意:
未完待续。。。