golang 版本 zookeeper 分布式鎖試驗隨筆


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成功
 */

 

// 創建一個永久父級路徑
// 之后的臨時路徑都在該永久路勁之下
// 這次實驗為 兩個實例創建一個相同節點

// 未完成 當多個實例中查詢結果都為該節點未創建,進入下一個階段,當其中一個實例搶占成功,其他則創建失敗,不應該直接返回創建失敗,應該重試多次,多次中返回則成功,否則失敗

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM