本文源碼:GitHub·點這里 || GitEE·點這里
一、框架簡介
1、基礎簡介
Zookeeper基於觀察者模式設計的組件,主要應用於分布式系統架構中的,統一命名服務、統一配置管理、統一集群管理、服務器節點動態上下線、軟負載均衡等場景。
2、集群選舉
Zookeeper集群基於半數機制,集群中半數以上機器存活,集群處於可用狀態。所以建議Zookeeper集群安裝為奇數台服務器。在集群的配置文件中並沒有指定Master和Slave。在Zookeeper工作時,是有一個節點為Leader,其他則為Follower,Leader是通過內部的選舉機制臨時產生的。
基本描述
假設有三台服務器組成的Zookeeper集群,每個節點的myid編號依次1-3,依次啟動服務器,會發現server2被選擇為Leader節點。
server1啟動,執行一次選舉。服務器1投自己一票。此時服務器1票數一票,未達到半數以上(2票),選舉無法完成,服務器1狀態保持為LOOKING;
server2啟動,再執行一次選舉。服務器1和2分別投自己一票,並交換選票信息,因為服務器2的myid比服務器1的myid大,服務器1會更改選票為投服務器2。此時服務器1票數0票,服務器2票數2票,達到半數以上,選舉完成,服務器1狀態為follower,2狀態保持leader,此時集群可用,服務器3啟動后直接為follower。
二、集群配置
1、創建配置目錄
# mkdir -p /data/zookeeper/data
# mkdir -p /data/zookeeper/logs
2、基礎配置
# vim /opt/zookeeper-3.4.14/conf/zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper/data
dataLogDir=/data/zookeeper/logs
clientPort=2181
3、單節點配置
# vim /data/zookeeper/data/myid
三個節點服務,分別在myid文件中寫入[1,2,3]
4、集群服務
在每個服務的zoo.cfg配置文件中寫入如下配置:
server.1=192.168.72.133:2888:3888
server.2=192.168.72.136:2888:3888
server.3=192.168.72.137:2888:3888
5、啟動集群
分別啟動三台zookeeper服務
[zookeeper-3.4.14]# bin/zkServer.sh start
Starting zookeeper ... STARTED
6、查看集群狀態
Mode: leader是Master節點
Mode: follower是Slave節點
[zookeeper-3.4.14]# bin/zkServer.sh status
Mode: leader
7、集群狀態測試
隨便登錄一台服務的客戶端,創建一個測試節點,然后在其他服務上查看。
[zookeeper-3.4.14 bin]# ./zkCli.sh
[zk: 0] create /node-test01 node-test01
Created /node-test01
[zk: 1] get /node-test01
或者關閉leader節點
[zookeeper-3.4.14 bin]# ./zkServer.sh stop
則會重新選舉該節點。
8、Nginx統一管理
[rnginx-1.15.2 conf]# vim nginx.conf
stream {
upstream zkcluster {
server 192.168.72.133:2181;
server 192.168.72.136:2181;
server 192.168.72.136:2181;
}
server {
listen 2181;
proxy_pass zkcluster;
}
}
三、服務節點監聽
1、基本原理
分布式系統中,主節點可以有多台,可以動態上下線,任意一台客戶端都能實時感知到主節點服務器的上下線。
流程描述:
- 啟動Zookeeper集群服務;
- RegisterServer模擬服務端注冊;
- ClientServer模擬客戶端監聽;
- 啟動服務端注冊三次,注冊不同節點的zk-node服務;
- 依次關閉注冊的服務端,模擬服務下線流程;
- 查看客戶端日志,可以監控到服務節點變化;
首先創建一個節點:serverList,用來存放服務器列表。
[zk: 0] create /serverList "serverList"
2、服務端注冊
package com.zkper.cluster.monitor;
import java.io.IOException;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.ZooDefs.Ids;
public class RegisterServer {
private ZooKeeper zk ;
private static final String connectString = "127.0.0.133:2181,127.0.0.136:2181,127.0.0.137:2181";
private static final int sessionTimeout = 3000;
private static final String parentNode = "/serverList";
private void getConnect() throws IOException{
zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent event) {
}
});
}
private void registerServer(String nodeName) throws Exception{
String create = zk.create(parentNode + "/server", nodeName.getBytes(),
Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println(nodeName +" 上線:"+ create);
}
private void working() throws Exception{
Thread.sleep(Long.MAX_VALUE);
}
public static void main(String[] args) throws Exception {
RegisterServer server = new RegisterServer();
server.getConnect();
// 分別啟動三次服務,注冊不同節點,再一次關閉不同服務端看客戶端效果
// server.registerServer("zk-node-133");
// server.registerServer("zk-node-136");
server.registerServer("zk-node-137");
server.working();
}
}
3、客戶端監聽
package com.zkper.cluster.monitor;
import org.apache.zookeeper.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class ClientServer {
private ZooKeeper zk ;
private static final String connectString = "127.0.0.133:2181,127.0.0.136:2181,127.0.0.137:2181";
private static final int sessionTimeout = 3000;
private static final String parentNode = "/serverList";
private void getConnect() throws IOException {
zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent event) {
try {
// 監聽在線的服務列表
getServerList();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private void getServerList() throws Exception {
List<String> children = zk.getChildren(parentNode, true);
List<String> servers = new ArrayList<>();
for (String child : children) {
byte[] data = zk.getData(parentNode + "/" + child, false, null);
servers.add(new String(data));
}
System.out.println("當前服務列表:"+servers);
}
private void working() throws Exception{
Thread.sleep(Long.MAX_VALUE);
}
public static void main(String[] args) throws Exception {
ClientServer client = new ClientServer();
client.getConnect();
client.getServerList();
client.working();
}
}
四、源代碼地址
GitHub·地址
https://github.com/cicadasmile/data-manage-parent
GitEE·地址
https://gitee.com/cicadasmile/data-manage-parent
推薦閱讀:數據和架構管理