package main import ( "fmt" "go-zookeeper/zk" "time" ) var ( flags int32 = zk.FlagEphemeral // 臨時節點 acls []zk.ACL = zk.WorldACL(zk.PermAll) // 權限 all parentPath string = "/lock" // parent path ZkHosts string = "129.204.83.47:2181" // zk address ) // 創建zookeeper鏈接,並創建永久父級節點 func NewZkConn(address,parentPath string) *zk.Conn{ hosts := []string{address} conn,_,err := zk.Connect(hosts,time.Second*5) if err != nil { panic(err) } ok,_,_ := conn.Exists(parentPath) if !ok { // 創建永久節點 nodeName,err := conn.Create(parentPath,nil,zk.FlagSequence,acls) if err != nil { panic(err) } fmt.Println("create node name :",nodeName) } return conn } func main() { conn := NewZkConn(ZkHosts,parentPath) // 假設臨時節點 path := parentPath + "/001_up_user" for i := 0;i<2;i++{ go func(conn *zk.Conn,path string,id int) { ok := t(conn,path,id) if ok { fmt.Printf("goroutine [%d] create node [%s] and wait 5s \n",id,path) time.Sleep(time.Second*5) err := conn.Delete(path,0) if err != nil { fmt.Println(err) } fmt.Printf("刪除成功 id為[%d] \n",id) }else { fmt.Printf("創建失敗id為[%d] \n",id) } }(conn,path,i) // (conn,fmt.Sprintf(path,i),i) } //_,s,event,err := conn.ExistsW(path) //for { // select { // case ch_event := <-event: // { // fmt.Println("path:", ch_event.Path) // fmt.Println("type:", ch_event.Type.String()) // fmt.Println("state:", ch_event.State.String()) // // if ch_event.Type == zk.EventNodeCreated { // fmt.Printf("has node[%s] detete\n", ch_event.Path) // } else if ch_event.Type == zk.EventNodeDeleted { // fmt.Printf("has new node[%d] create\n", ch_event.Path) // } else if ch_event.Type == zk.EventNodeDataChanged { // fmt.Printf("has node[%d] data changed", ch_event.Path) // } // } // } //} time.Sleep(time.Second*60) } func t(conn *zk.Conn,path string,id int) bool{ fmt.Printf("第 [%d] 個goroutine \n",id) // 設置條件,避免多個goroutine並發請求返回結果都為 節點未創建狀態 搶占建立節點 if id == 1{ time.Sleep(time.Second*1) //list, _, zz, _ :=conn.ChildrenW("/lock") //for _,v := range list{ // fmt.Println(v) //} //z := <-zz //fmt.Println(z) } ok,_,ch,err := conn.ExistsW(path) if err != nil { return false } ex := false if ok { fmt.Printf("goroutine [%d] 節點 [%s] 已存在\n",id,path) for { fmt.Printf("goroutine [%d] 監控節點狀態ing...",id) select { case c := <-ch: { //fmt.Println("path:", c.Path) //fmt.Println("type:", c.Type.String()) //fmt.Println("state:", c.State.String()) if c.Type == zk.EventNodeDeleted { fmt.Printf("other node delete,current node[%s] id [%d]\n", c.Path,id) ex = true break } } } if ex { break } } } fmt.Printf("當前id為[%d] 節點 [%s] 不存在並創建 \n",id,path) _,err = conn.Create(path,nil,flags,acls) if err != nil { fmt.Printf("創建失敗 [%s] 當前節點為[%d] 原因可能為 節點被搶占 or zk宕機",path,id) return false } fmt.Printf("[%s] 創造節點的id為 [%d] \n",path,id) return true } /* 貌似這個庫沒有實現監控,只能已以下方式實現 exists(path) // path 為用戶id_操作行為_操作方法名 當給節點存在則進行輪詢n次是否刪除 如果刪除則進行創建,注意是否其他分布式實例是否搶占先創建了節點 -如果創建失敗 輪詢 3 次是否刪除,刪除則創建,如果失敗則直接退出,返回lock失敗 -創建成功返回lock成功 */
// 創建一個永久父級路徑 // 之后的臨時路徑都在該永久路勁之下 // 這次實驗為 兩個實例創建一個相同節點 // 未完成 當多個實例中查詢結果都為該節點未創建,進入下一個階段,當其中一個實例搶占成功,其他則創建失敗,不應該直接返回創建失敗,應該重試多次,多次中返回則成功,否則失敗