【GO】27. zookeeper golang庫go-zookeeper例項

chen_peng7發表於2020-10-19

Golang 操作 zookeeper

使用庫:https://github.com/samuel/go-zookeeper

文件地址:http://godoc.org/github.com/samuel/go-zookeeper/zk

 

連線zk server

package main

import (
	"fmt"
	"github.com/samuel/go-zookeeper/zk"
	"time"
)

func main() {
	// 建立zk連線地址
	hosts := []string{"127.0.0.1:2181"}
	// 連線zk
	conn, _, err := zk.Connect(hosts, time.Second*5)
	defer conn.Close()
	if err != nil {
		fmt.Println(err)
		return
	}
	println(conn.Server())
}

 

增刪改查

package main

import (
	"fmt"
	"github.com/samuel/go-zookeeper/zk"
	"time"
)

var (
	path = "/test"
)

// 增
func add(conn *zk.Conn) {
	var data = []byte("test value")
	// flags有4種取值:
	// 0:永久,除非手動刪除
	// zk.FlagEphemeral = 1:短暫,session斷開則該節點也被刪除
	// zk.FlagSequence  = 2:會自動在節點後面新增序號
	// 3:Ephemeral和Sequence,即,短暫且自動新增序號
	var flags int32 = 0
	// 獲取訪問控制許可權
	acls := zk.WorldACL(zk.PermAll)
	s, err := conn.Create(path, data, flags, acls)
	if err != nil {
		fmt.Printf("建立失敗: %v\n", err)
		return
	}
	fmt.Printf("建立: %s 成功", s)
}

// 查
func get(conn *zk.Conn) {
	data, _, err := conn.Get(path)
	if err != nil {
		fmt.Printf("查詢%s失敗, err: %v\n", path, err)
		return
	}
	fmt.Printf("%s 的值為 %s\n", path, string(data))
}

// 刪改與增不同在於其函式中的version引數,其中version是用於 CAS支援
// 可以通過此種方式保證原子性
// 改
func modify(conn *zk.Conn) {
	new_data := []byte("hello zookeeper")
	_, sate, _ := conn.Get(path)
	_, err := conn.Set(path, new_data, sate.Version)
	if err != nil {
		fmt.Printf("資料修改失敗: %v\n", err)
		return
	}
	fmt.Println("資料修改成功")
}

// 刪
func del(conn *zk.Conn) {
	_, sate, _ := conn.Get(path)
	err := conn.Delete(path, sate.Version)
	if err != nil {
		fmt.Printf("資料刪除失敗: %v\n", err)
		return
	}
	fmt.Println("資料刪除成功")
}

func main() {
	// 建立zk連線地址
	hosts := []string{"127.0.0.1:2181"}
	// 連線zk
	conn, _, err := zk.Connect(hosts, time.Second*5)
	defer conn.Close()
	if err != nil {
		fmt.Println(err)
		return
	}

	/* 增刪改查 */
	//add(conn)
	//get(conn)
	//modify(conn)
	del(conn)
	get(conn)
}

 

watch機制

1.呼叫zk.WithEventCallback(callback)設定回撥

package main

import (
	"fmt"
	"github.com/samuel/go-zookeeper/zk"
	"time"
)

var (
	hosts       = []string{"127.0.0.1:2181"}
	path        = "/wtzk"
	flags int32 = zk.FlagEphemeral
	data        = []byte("zk data 001")
	acls        = zk.WorldACL(zk.PermAll)
)

func main() {
	// 建立監聽的option,用於初始化zk
	eventCallbackOption := zk.WithEventCallback(callback)
	// 連線zk
	conn, _, err := zk.Connect(hosts, time.Second*5, eventCallbackOption)
	defer conn.Close()
	if err != nil {
		fmt.Println(err)
		return
	}

	// 開始監聽path
	_, _, _, err = conn.ExistsW(path)
	if err != nil {
		fmt.Println(err)
		return
	}

	// 觸發建立資料操作
	create(conn, path, data)

	//再次監聽path
	_, _, _, err = conn.ExistsW(path)
	if err != nil {
		fmt.Println(err)
		return
	}
	// 觸發刪除資料操作
	del(conn, path)

}

// zk watch 回撥函式
func callback(event zk.Event) {
	// zk.EventNodeCreated
	// zk.EventNodeDeleted
	fmt.Println("###########################")
	fmt.Println("path: ", event.Path)
	fmt.Println("type: ", event.Type.String())
	fmt.Println("state: ", event.State.String())
	fmt.Println("---------------------------")
}

// 建立資料
func create(conn *zk.Conn, path string, data []byte) {
	_, err := conn.Create(path, data, flags, acls)
	if err != nil {
		fmt.Printf("建立資料失敗: %v\n", err)
		return
	}
	fmt.Println("建立資料成功")
}

// 刪除資料
func del(conn *zk.Conn, path string) {
	_, stat, _ := conn.Get(path)
	err := conn.Delete(path, stat.Version)
	if err != nil {
		fmt.Printf("刪除資料失敗: %v\n", err)
		return
	}
	fmt.Println("刪除資料成功")
}

 

2.部分監聽:

1.呼叫conn.ExistsW(path) 或GetW(path)為對應節點設定監聽,該監聽只生效一次
2.開啟一個協程處理chanel中傳來的event事件
(注意:watchCreataNode一定要放在一個協程中,不能直接在main中呼叫,不然會阻塞main)

package main

import (
	"fmt"
	"github.com/samuel/go-zookeeper/zk"
	"time"
)

var (
	hosts       = []string{"127.0.0.1:2181"}
	path        = "/wtzk"
	flags int32 = zk.FlagEphemeral
	data        = []byte("zk data 001")
	acls        = zk.WorldACL(zk.PermAll)
)

func main() {
	// 連線zk
	conn, _, err := zk.Connect(hosts, time.Second*5)
	defer conn.Close()
	if err != nil {
		fmt.Println(err)
		return
	}

	// 開始監聽path
	_, _, event, err := conn.ExistsW(path)
	if err != nil {
		fmt.Println(err)
		return
	}

	// 協程呼叫監聽事件
	go watchZkEvent(event)

	// 觸發建立資料操作
	create(conn, path, data)

}

// zk 回撥函式
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 create(conn *zk.Conn, path string, data []byte) {
	_, err := conn.Create(path, data, flags, acls)
	if err != nil {
		fmt.Printf("建立資料失敗: %v\n", err)
		return
	}
	fmt.Println("建立資料成功")
}

1.如果即設定了全域性監聽又設定了部分監聽,那麼最終是都會觸發的,並且全域性監聽在先執行
2.如果設定了監聽子節點,那麼事件的觸發是先子節點後父節點

 

客戶端隨機hostname支援

最終就是Round Robin策略

var hosts = []string{"host01:2181", "host02:2181", "host03:2181",}
hostPro := new(zk.DNSHostProvider)
//先初始化
err := hostPro.Init(hosts)

if err != nil {
	fmt.Println(err)
	return
}
//獲得host
server, retryStart := hostPro.Next()
fmt.Println(server, retryStart)
//連線成功後會呼叫
hostPro.Connected()

 

相關文章