系统协调 zookeeper+golang入门

官网: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")
	}
}

测试截图
系统协调 zookeeper+golang入门_第1张图片

观察者机制

部分监听

首先声明一个回调函数

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函数

  • 在进行连接的时候声明回调函数zk.WithEventCallback(CallBlack)
  • ExistsW 方法注册观察那个path创建
  • 注意:当监听的path添加时只调用一次回调函数,一次后失效,想重新观察需要重新执行ExistsW
  • GetW和ExistsW特性类似,用于监听get
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
}

注意:

  • 如果即设置了全局监听又设置了部分监听,那么最终是都会触发的,并且全局监听在先执行
  • 如果设置了监听子节点,那么事件的触发是先子节点后父节点

未完待续。。。

你可能感兴趣的:(Golang,微服务)