我是靠谱客的博主 缥缈小熊猫,这篇文章主要介绍基于Zookeeper集群环境下的负载均衡,现在分享给大家,希望可以做个参考。

转载请说明出处:https://blog.csdn.net/LiaoHongHB/article/details/84973879

1、原理

  • 服务端启动创建临时节点(下图中servers下节点),临时节点数据包含负载信息
  • 客户端启动获取服务器列表,并根据负载去连接一个负载较轻的服务器
  • 服务端每次接收到客户端的连接,添加自己的负载,客户端断开与自己的连接则减少自己的负载

2、架构图

  • Servers:服务器列表父节点
  • work Server n :服务器节点
  • Client n:客户端节点

3、客户端流程图

 

 

4、服务端流程图

5、新建工程zookeeper-balance,并新建子模块:balance-server1, balance-server2,balance-server2,balance-client,balance-client2,balance-client3以及balance-common。

6、balance-common:通用模块,只有一个ServerData类,用于存储各个工作服务器节点的数据信息

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class ServerData implements Serializable { private static final long serialVersionUID = 2965518573348700597L; private String serverName; private String serverIp; private Integer balanceNum; public String getServerName() { return serverName; } public void setServerName(String serverName) { this.serverName = serverName; } public String getServerIp() { return serverIp; } public void setServerIp(String serverIp) { this.serverIp = serverIp; } public Integer getBalanceNum() { return balanceNum; } public void setBalanceNum(Integer balanceNum) { this.balanceNum = balanceNum; } }

7、balance-server1:工作服务器,服务注册到zookeeper集群中,并且监听自己节点的负载数的数据变化;balance-server2和balance-server3同balance-server1.

WorkServer:功能实现类:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class WorkServer { private Logger logger = LoggerFactory.getLogger(getClass()); private ZkClient zkClient = null; private String serverPath; private int SESSIONTIMEOUT = 15000; private int CONNECTIONTIMEOUT = 15000; private ServerData serverData; public WorkServer() { } public WorkServer(String ipAddress, String serverPath, ServerData serverData) { this.zkClient = new ZkClient(ipAddress, SESSIONTIMEOUT, CONNECTIONTIMEOUT, new SerializableSerializer()); this.serverPath = serverPath; this.serverData = serverData; } public void start() { logger.info("balance-server1启动,准备初始化...."); init(); } public void init() { logger.info("balance-server1 开始初始化...."); boolean exists = zkClient.exists(serverPath); if (!exists) { zkClient.createPersistent(serverPath); logger.info("创建{}持久节点成功", serverPath); } boolean exists1 = zkClient.exists(serverPath.concat(serverData.getServerName())); if (!exists1) { zkClient.createEphemeral(serverPath.concat(serverData.getServerName()), serverData); logger.info("创建{}临时节点成功", serverPath.concat(serverData.getServerName())); } zkClient.subscribeDataChanges(serverPath.concat(serverData.getServerName()), new IZkDataListener() { @Override public void handleDataChange(String s, Object o) throws Exception { logger.info("节点{}数据发生改变...", s); } @Override public void handleDataDeleted(String s) throws Exception { logger.info("节点{}被删除.....", s); } }); } }

WebListener:启动类;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Component public class WebListener implements ServletContextListener { private Logger logger = LoggerFactory.getLogger(getClass()); private String ipAddress = "192.168.202.128:2181,192.168.202.129:2181,192.168.202.130:2181"; @Override public void contextInitialized(ServletContextEvent sce) { ServerData serverData = new ServerData(); serverData.setBalanceNum(0); serverData.setServerIp("192.168.202.128"); serverData.setServerName("/WorkServer1"); WorkServer workServer = new WorkServer(ipAddress, "/servers", serverData); workServer.start(); } @Override public void contextDestroyed(ServletContextEvent sce) { } }

 

8、balance-client1:客户端,负载均衡的访问工作服务器,balance-client2和balance-client3同balance-client1。

Client1:功能实现类;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
public class Client1 { private Logger logger = LoggerFactory.getLogger(getClass()); private ZkClient zkClient = null; private String serverPath; private int SESSIONTIMEOUT = 15000; private int CONNECTIONTIMEOUT = 15000; public Client1() { } public Client1(String ipAddress, String serverPath) { this.zkClient = new ZkClient(ipAddress, SESSIONTIMEOUT, CONNECTIONTIMEOUT, new SerializableSerializer()); this.serverPath = serverPath; } public void start() { logger.info("client1 服务启动,准备初始化..."); init(); } public void init() { logger.info("client1 开始初始化..."); logger.info("获取{}节点的子节点...", serverPath); List<String> children = getChildren(); logger.info("{}子节点有{}:", serverPath, children.toString()); logger.info("client1 使用负载均衡调用工作服务器进行工作...."); String node = balance(children); // release(node); try { Thread.sleep(10000); } catch (Exception e) { e.printStackTrace(); } } /** * 获取serverPath的子节点列表 * * @return */ public List<String> getChildren() { List<String> list = zkClient.getChildren(serverPath); List<String> list1 = new ArrayList<>(); for (String string : list) { string = "/servers/".concat(string); list1.add(string); } return list1; } /** * 判断哪个工作服务器负载最小 * * @param children */ public String balance(List<String> children) { List<Integer> integerList = new ArrayList<>(); for (String string : children) { ServerData serverData = zkClient.readData(string); Integer balanceNum = serverData.getBalanceNum(); integerList.add(balanceNum); } Collections.sort(integerList); for (String string : children) { ServerData serverData = zkClient.readData(string); Integer balanceNum = serverData.getBalanceNum(); Integer minBalanceNum = integerList.get(0); if (balanceNum.equals(minBalanceNum)) { logger.info("调用{}节点对应的服务器进行服务", string); balanceNum++; serverData.setBalanceNum(balanceNum); logger.info("更新{}节点负载情况", string); zkClient.writeData(string, serverData); return string; } } return null; } /** * 调用完毕,释放负载 * * @param string */ public void release(String string) { logger.info("释放{}节点的负载", string); ServerData serverData = (ServerData) zkClient.readData(string); serverData.setBalanceNum(serverData.getBalanceNum() - 1); zkClient.writeData(string, serverData); } }

9、运行及运行结果:首先运行server模块,然后运行client模块;运行结果如下:

 

 

 

 

如果重新启动client2或者client3,则根据负载数,又会去调用server1的工作服务器 :

 

 

最后

以上就是缥缈小熊猫最近收集整理的关于基于Zookeeper集群环境下的负载均衡的全部内容,更多相关基于Zookeeper集群环境下内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(55)

评论列表共有 0 条评论

立即
投稿
返回
顶部