CentOS environment installs zookeeper service and uses golang to implement Leader election of distributed system

Keywords: Go Zookeeper CentOS git firewall

I. Preparations

1. Download and install vmware, the steps are omitted.

2. Download the ios package for the CentOS system: http://isoredirect.centos.org/centos/7/isos/x86_64/CentOS-7-x86_64-Everything-1611.iso

3. Download and install Xshell 5, step omitted.

4. Download and install git, step omitted.

5.zookeeper official website: http://zookeeper.apache.org/

6.zookeeper api for golang: https://github.com/samuel/go-zookeeper

7. In vmware, click "Create a New Virtual Machine" - > "Typical" - > "Installer CD-ROM Image File" to select the ios file downloaded above, and then quickly install the CentOS system in the next step along the way.

As for why CentOS is installed, other linux versions are also available. The installed CentOS system is as follows:

 

II. Installation and configuration of zookeeper

Click Applications in the upper left corner of the screen, open Terminal, and download zookeeper to the / usr/local directory, which can be understood as C:/Progrem Files/directory under windows.

First switch to root permission:

Enter su, return to the train, see Password: Enter the password, note that the password will not be displayed, just enter directly after the completion of the train.

Next, execute the command to enter the / usr/local directory:

cd /usr/local

Download zookeeper-3.5.3-beta.tar.gz:

wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.5.3-beta/zookeeper-3.5.3-beta.tar.gz

There will be a download progress bar in terminal. After reading the progress bar, the file will be downloaded. We will decompress it first.

tar -xvf zookeeper-3.5.3-beta.tar.gz

 

Next we go to the conf directory to set up:

cd zookeeper-3.5.3-beta/conf/

Copy the zoo_sample.cfg file and name it zoo.cfg:

cp zoo_sample.cfg zoo.cfg

We edit zoo.cfg to set up the relevant settings:

vi zoo.cfg

At this time, if you want to modify the content of this file, press the "i" key on the keyboard, the bottom will become INSERT, you can modify it.

Move the cursor to

dataDir=/tmp/zookeeper

Change to

dataDir=/usr/local/zookeeper-3.5.3-beta

 

Press Esc to exit editing mode, then enter: wq Enter to save and close the file.

 

Let's take a look at the LAN ip address of the virtual machine:

ifconfig

 

You can see that the IP address of my virtual machine is 192.168.40.129.

We need to use a software xshell 5 here. Actually, it runs under the terminal of CentOS. But if zookeeper is installed on the server side instead of on the local virtual machine, it will be more convenient to use xshell 5, so we use xshell 5 here.

Open xshell 5 and log in to our virtual machine:

 

The user name is root, and the password is the password of the virtual machine.

Enter zookeeper's runtime directory:

cd /usr/local/zookeeper-3.5.3-beta/bin

Let's start zookeeper's service:

./zkServer.sh start

 

The appearance of STARTED indicates that our zookeeper has been started. We can do some simple operations directly from the command line through the client side provided by STARTED, and input:

./zkCli.sh

You can see that we have entered the client side of zookeeper.

 

Enter help to view commands from the command line.

 

3. Leader Election of Distributed System by Goang

Next, we use zookeeper and golang to implement Leader election in distributed system.

Installing and configuring the golang environment is not the focus of this article. It is omitted here.

We can use git to get it. Git can download and install it by itself. Here is the GIT command.

Look at the location of golang:

which go

Set GOROOT:

export GOROOT=/c/Go

I put the golang program under the golang folder of the d disk, then set GOPATH:

export GOPATH=/d/golang/

Get the api of zookeeper for go:

go get github.com/samuel/go-zookeeper/zk

Next, create a go project under the golang folder of the d disk, and write the following code to simulate the Leader election process:

package main

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

type ZookeeperConfig struct {
	Servers    []string
	RootPath   string
	MasterPath string
}

type ElectionManager struct {
	ZKClientConn *zk.Conn
	ZKConfig     *ZookeeperConfig
	IsMasterQ    chan bool
}

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

func (electionManager *ElectionManager) Run() {
	err := electionManager.electMaster()
	if err != nil {
		fmt.Println("elect master error, ", err)
	}
	electionManager.watchMaster()
}

// Determine whether the connection to zookeeper was successful
func (electionManager *ElectionManager) isConnected() bool {
	if electionManager.ZKClientConn == nil {
		return false
	} else if electionManager.ZKClientConn.State() != zk.StateConnected {
		return false
	}
	return true
}

// Initialize zookeeper connection
func (electionManager *ElectionManager) initConnection() error {
	// Get a connection to the zookeeper server if the connection is empty or unsuccessful
	if !electionManager.isConnected() {
		conn, connChan, err := zk.Connect(electionManager.ZKConfig.Servers, time.Second)
		if err != nil {
			return err
		}
		// Waiting for the connection to succeed
		for {
			isConnected := false
			select {
			case connEvent := <-connChan:
				if connEvent.State == zk.StateConnected {
					isConnected = true
					fmt.Println("connect to zookeeper server success!")
				}
			case _ = <-time.After(time.Second * 3): // Return connection timeout after 3 seconds of unsuccessful connection
				return errors.New("connect to zookeeper server timeout!")
			}
			if isConnected {
				break
			}
		}
		electionManager.ZKClientConn = conn
	}
	return nil
}

// Election master
func (electionManager *ElectionManager) electMaster() error {
	err := electionManager.initConnection()
	if err != nil {
		return err
	}
	// Determine whether the root directory exists in zookeeper and create it if it does not exist
	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("Create returned different path " + electionManager.ZKConfig.RootPath + " != " + path)
		}
	}

	// Create a ZNode for electing master, which is Ephemeral type, indicating that when the client disconnects, the created node will be destroyed
	masterPath := electionManager.ZKConfig.RootPath + electionManager.ZKConfig.MasterPath
	path, err := electionManager.ZKClientConn.Create(masterPath, nil, zk.FlagEphemeral, zk.WorldACL(zk.PermAll))
	if err == nil { // Create success to indicate election master success
		if path == masterPath {
			fmt.Println("elect master success!")
			electionManager.IsMasterQ <- true
		} else {
			return errors.New("Create returned different path " + masterPath + " != " + path)
		}
	} else { // Creation failure indicates election master failure
		fmt.Printf("elect master failure, ", err)
		electionManager.IsMasterQ <- false
	}
	return nil
}

// Monitor master znode in zookeeper, if deleted, indicating master failure or network delay, re-election
func (electionManager *ElectionManager) watchMaster() {
	for {
		// The sub-znode under watch zk root znode is deleted when a connection is disconnected and re-elected after triggering an event
		children, state, childCh, err := electionManager.ZKClientConn.ChildrenW(electionManager.ZKConfig.RootPath + electionManager.ZKConfig.MasterPath)
		if err != nil {
			fmt.Println("watch children error, ", err)
		}
		fmt.Println("watch children result, ", children, state)
		select {
		case childEvent := <-childCh:
			if childEvent.Type == zk.EventNodeDeleted {
				fmt.Println("receive znode delete event, ", childEvent)
				// Reelection
				fmt.Println("start elect new master ...")
				err = electionManager.electMaster()
				if err != nil {
					fmt.Println("elect new master error, ", err)
				}
			}
		}
	}
}
func main() {
	// zookeeper configuration
	zkConfig := &ZookeeperConfig{
		Servers:    []string{"192.168.40.129"},
		RootPath:   "/ElectMasterDemo",
		MasterPath: "/master",
	}
	// The channel of communication between the main goroutine and the election goroutine is the same as returning the result of the election.
	isMasterChan := make(chan bool)

	var isMaster bool

	// Election
	electionManager := NewElectionManager(zkConfig, isMasterChan)
	go electionManager.Run()

	for {
		select {
		case isMaster = <-isMasterChan:
			if isMaster {
				// do some job on master
				fmt.Println("do some job on master")
			}
		}
	}
}

 

Among them, the ip of main function is rewritten to the virtual machine ip found above.

Enter in Xshell 5:

ls /

We can see that there is only one zookeeper in the current root directory.

To successfully call zookeeper using golang program, we need to turn off the firewall under our CentOS system.

Enter in Xshell 5:

systemctl | grep fire

You can see that the firewall is running.

Let's stop the firewall first:

stop firewalld

Then disable firewalls:

disable firewalld

Save and modify:

iptables-save

 

After successfully shutting down the firewall and running the go program mentioned above, we can see that the first process succeeded as leader:

GOROOT=C:\Go
GOPATH=D:/golang
C:\Go\bin\go.exe build -i -o C:\Users\renjiashuo\AppData\Local\Temp\Build_main_go_and_rungo D:/golang/src/leader/main.go
"C:\Program Files\JetBrains\IntelliJ IDEA 2017.1.5\bin\runnerw.exe" C:\Users\renjiashuo\AppData\Local\Temp\Build_main_go_and_rungo
connect to zookeeper server success!
2017/07/27 21:02:38 Connected to 192.168.40.129:2181
2017/07/27 21:02:38 Authenticated: id=72057981844586499, timeout=4000
2017/07/27 21:02:38 Re-submitting `0` credentials after reconnect
elect master success!
do some job on master
watch children result,  [] &{9 9 1501160558009 1501160558009 0 0 0 72057981844586499 0 0 9}

  

Do not close this program and execute another go program. We can see that because the first process has become the leader, the second process can only wait:

GOROOT=C:\Go
GOPATH=D:/golang
C:\Go\bin\go.exe build -i -o C:\Users\renjiashuo\AppData\Local\Temp\Build_main_go_and_run1go D:/golang/src/leader/main.go
"C:\Program Files\JetBrains\IntelliJ IDEA 2017.1.5\bin\runnerw.exe" C:\Users\renjiashuo\AppData\Local\Temp\Build_main_go_and_run1go
connect to zookeeper server success!
2017/07/27 21:05:29 Connected to 192.168.40.129:2181
2017/07/27 21:05:29 Authenticated: id=72057981844586500, timeout=4000
2017/07/27 21:05:29 Re-submitting `0` credentials after reconnect
elect master failure, %!(EXTRA *errors.errorString=zk: node already exists)watch children result,  [] &{9 9 1501160558009 1501160558009 0 0 0 72057981844586499 0 0 9}

  

When we close the first process, we can see the change of the second process.

GOROOT=C:\Go
GOPATH=D:/golang
C:\Go\bin\go.exe build -i -o C:\Users\renjiashuo\AppData\Local\Temp\Build_main_go_and_run1go D:/golang/src/leader/main.go
"C:\Program Files\JetBrains\IntelliJ IDEA 2017.1.5\bin\runnerw.exe" C:\Users\renjiashuo\AppData\Local\Temp\Build_main_go_and_run1go
connect to zookeeper server success!
2017/07/27 21:05:29 Connected to 192.168.40.129:2181
2017/07/27 21:05:29 Authenticated: id=72057981844586500, timeout=4000
2017/07/27 21:05:29 Re-submitting `0` credentials after reconnect
elect master failure, %!(EXTRA *errors.errorString=zk: node already exists)watch children result,  [] &{9 9 1501160558009 1501160558009 0 0 0 72057981844586499 0 0 9}
receive znode delete event,  {EventNodeDeleted Unknown /ElectMasterDemo/master <nil> }
start elect new master ...
connect to zookeeper server success!
2017/07/27 21:06:28 Connected to 192.168.40.129:2181
2017/07/27 21:06:28 Authenticated: id=72057981844586501, timeout=4000
2017/07/27 21:06:28 Re-submitting `0` credentials after reconnect
elect master success!
do some job on master
watch children result,  [] &{14 14 1501160787685 1501160787685 0 0 0 72057981844586501 0 0 14}

  

The second process succeeded as leader.

The annotations of the program code are more detailed, but not detailed here. All api interfaces invoked can be accessed to view their go source code.

Since then, the centrOS environment has installed zookeeper service and implemented Leader election of distributed system with golang.

Posted by Canadiengland on Sun, 09 Jun 2019 14:25:53 -0700