超细!细说Zookeeper选举的一个案例(上)

2,221 阅读3分钟

作者:ReganYue

来源:恒生LIGHT云社区

超细!细说Zookeeper选举的一个案例

今天我们来带着大家实现用Zookeeper实现选举的案例,帮助大家更好的学习Zookeeper。

一、安装所需第三方库

使用Go来对Zookeeper进行操作需要使用 go get github.com/samuel/go-zookeeper/zk 。根据GitHub上有关它的描述它是一个Zookeeper客户端~

当然现在它的最新仓库地址是 https://github.com/go-zookeeper/zk

你也可以下载这个仓库的第三方库。

二、定义配置信息和选举管理信息的结构体

type ZookeeperConfig struct {
  Servers   []string
  RootPath   string
  MasterPath string
}
​
type ElectionManager struct {
  ZKClinet *zk.Conn
  ZkConfig *ZookeeperConfig
  IsMaster chan bool
}

配置信息就是包含zookeeper集群服务器地址,根路径以及它的Master节点路径。

选举管理信息包括zookeeper的连接信息、zookeeper的配置信息、以及传递选举信息的管道。

三、程序主逻辑

func main() {
  zkconfig := &ZookeeperConfig{
      Servers:   []string{"node01:2181", "node02:2181", "node03:2181"},
      RootPath:   "/test04",
      MasterPath: "/master",
  }
​
  isMasterChan := make(chan bool)
  electionManager := NewElectionManager(zkconfig, isMasterChan)
​
  go electionManager.Run()
​
  var isMaster bool
  for {
      select {
      case isMaster = <-isMasterChan:
          if isMaster {
              fmt.Println("实现具体的业务逻辑")
          }
      }
  }
​
}

这个zkconfig是填入咱们要使用的zookeeper集群配置信息,isMasterChan建立用于返回选取结果的信道,然后创建选举管理器,正如我们平时的选举有选举委员会一样,zookeeper的选举也需要选举管理器。然后开辟协程来进行选举: go electionManager.Run() ,除了每次启动集群时会选举主节点之外,还需要监视主节点,如果主节点出问题了,需要立刻选举出一个新的主节点。下面的isMaster是判断是否是主节点,是通过信道的返回值来判断的。然后下面的for循环,就是不断从管道中读取选举结果,是否成功,如果成功表示集群可以正常运作了,就可以实现具体的业务逻辑了,如果没选举成功就只能一直等待了。

四、创建选举管理器

func NewElectionManager(zkConfig *ZookeeperConfig, isMaster chan bool) *ElectionManager {
  electionManager := &ElectionManager{
    nil,
    zkConfig,
    isMaster,
  }
​
  electionManager.initConnection()
​
  return electionManager
}

创建选举管理器比较简单,就是输入一些配置信息,来初始化连接,然后将初始化后的选举管理器传递出去。

五、初始化Zookeeper连接

在创建选举管理器中用到了初始化Zookeeper连接的方法,实现如下:

func (electionManager *ElectionManager) initConnection() error {
  if !electionManager.isConnected() {
    conn, connChan, err := zk.Connect(electionManager.ZKConfig.Servers, time.Second*5)
    if err != nil {
        return err
    }
    for {
        isConnected := false
        select {
        case connEvcent := <-connChan:
          if connEvcent.State == zk.StateConnected {
              isConnected = true
              fmt.Println("zk连接成功")
          }
        case _ = <-time.After(time.Second * 3):
          return errors.New("zk连接超时!")
        }
        if isConnected {
          break
        }
    }
    electionManager.ZKClientConn = conn
  }
  return nil
}

先是判断是否已经连接Zookeeper,如果连接有问题,或者没有连接的情况下就进行连接zookeeper。

下面来介绍这个zk.Connect,Connect 用于建立到 Zookeeper 服务器池的新连接。第一个参数是服务器集群地址,第二个参数是在失去与服务器的连接后当前会话仍被视为有效的时间量。 在会话超时之前,可以重新建立到不同服务器的连接并保持相同的会话。 这样可以维护和监控任何临时节点。

然后就是进入循环,不断去connChan取东西,当connChan是zk.StateConnected时,表示连接成功,就给isConnected赋值为true,如果3秒都未成功,则报错连接超时。当连接成功时跳出这个for循环, electionManager.ZKClientConn = conn表示将获得的连接给选举管理器的连接。