作者:ReganYue
起源:恒生 LIGHT 云社区
超细!细说 Zookeeper 选举的一个案例
明天咱们来带着大家实现用 Zookeeper 实现选举的案例,帮忙大家更好的学习 Zookeeper。
六、判断是否连贯 Zookeeper
func (electionManager *ElectionManager) isConnected() bool {
if electionManager.ZKClientConn == nil {return false} else if electionManager.ZKClientConn.State() != zk.StateConnected {return false}
return true
}
在初始化 Zookeeper 连贯时须要判断是否连贯了 Zookeeper,其实咱们能够看连贯是否为 nil 值来判断有没有连贯,如果想判断连贯是否有问题的话,咱们最好用连贯的 State() 办法,如果是 zk.StateConnected,就示意连贯胜利了,如果是其余就示意连贯异样,上面列举连贯异样和胜利的值。
StateUnknown State = -1
StateDisconnected State = 0
StateConnecting State = 1
StateAuthFailed State = 4
StateConnectedReadOnly State = 5
StateSaslAuthenticated State = 6
StateExpired State = -112
StateConnected = State(100)
StateHasSession = State(101)
能够看到,zk.StateConnected 也就是 100,所以这里可能能够将 zk.StateConnected 替换为 100,我也不晓得是否可行,你能够试一试~ StateUnknown 也就是 - 1 示意状态是未知的,StateDisconnected 也就是 0 示意状态是未连贯,其它我就不细说了。
七、选举的逻辑
func (electionManager *ElectionManager) Run() {err := electionManager.electMaster()
if err != nil {fmt.Println(err)
}
electionManager.watchMaster()}
是不是很眼生,这就是 main 函数中开拓协程运行的货色——选举。
很简略,间接进行选举选出 master,而后对 master 节点进行监听。
八、选举逻辑
func (electionManager *ElectionManager) electMaster() error {err := electionManager.initConnection()
if err != nil {return err}
isExist, _, err := electionManager.ZKClientConn.Exists(electionManager.ZKConfig.RootPath)
if err != nil {return err}
if !isExist {
path, err := electionManager.ZKClientConn.Create(electionManager.ZKConfig.RootPath,
nil, 0, zk.WorldACL(zk.PermAll))
if err != nil {return err}
if electionManager.ZKConfig.RootPath != path {return errors.New("创立的" + electionManager.ZKConfig.RootPath + "!=" + path)
}
}
masterPath := electionManager.ZKConfig.RootPath + electionManager.ZKConfig.MasterPath
path, err := electionManager.ZKClientConn.Create(masterPath, nil, zk.FlagEphemeral, zk.WorldACL(zk.PermAll))
if err == nil {
if path == masterPath {fmt.Println("选举 master 胜利")
electionManager.IsMaster <- true
} else {return errors.New("创立的" + masterPath + "!=" + path)
}
} else {
// 创立 master 节点失败
fmt.Println("选举 master 失败!", err)
electionManager.IsMaster <- false
}
return nil
}
要开始选举,必须要先连贯 Zookeeper,咱们编写的 initConnection() 进行连贯 zk 并能够通过返回值来判断连贯是否有问题。
而后判断 zk 中是否存在根目录,如果没有,就创立根目录,根目录个别数据先不设置,flags 是为 0,要创立长久化节点,权限不进行管制。
来介绍一下这个 Create() 叭~
Create() 有四个参数,第一个是要创立的门路,第二个参数是节点中的数据内容,第三个参数是节点类型参数,flag= 0 示意这是一个长久化的节点,第四个参数是权限。有上面这些权限。
PermRead = 1 << iota
PermWrite
PermCreate
PermDelete
PermAdmin
PermAll = 0x1f
应用 zk.WorldACL(zk.PermAll) 示意该节点没有权限限度
而后再拼接 master 地址,创立 master 节点,因为须要创立个长期节点,所以 Create() 中的第三个参数参数应用 zk.FlagEphemeral 示意创立长期节点。创立胜利,示意选举 master 胜利,哪个客户端节点创立了 master,认为是选举哪个节点作为 master 节点。
创立胜利后要给连贯的 isMaster 写入 true,不胜利则写入 false。
九、监听 Master 节点
func (electionManager *ElectionManager) watchMaster() error {
for {children, state, childCh, err := electionManager.ZKClientConn.ChildrenW(electionManager.ZKConfig.RootPath + electionManager.ZKConfig.MasterPath)
if err != nil {fmt.Println("监听失败!", err)
}
fmt.Println("监听到子节点", children, state)
select {
case childEvent := <-childCh:
if childEvent.Type == zk.EventNodeDeleted {fmt.Println("接管到 znode 的删除事件", childEvent)
fmt.Println("开始选举新的 master...")
err = electionManager.electMaster()
if err != nil {fmt.Println("选举新的 master 失败", err)
}
}
}
}
}
须要监听 zookeeper 根节点下的子节点,因为如果连贯断开或对应的子 znode 被删除,则触发从新选举,所以须要监听目录下所有子节点。
ChildrenW() 会返回监听事件,如果监听到子节点被删除,也就是监听到的事件类型是 zk.EventNodeDeleted,就从新调用 electMaster() 进行选举。