1:Zookeeper基础
安装zookeeper。当然,很多时候我们会在Windows上开发,所以,我们需要在本地搭建一个zookeeper环境。方便开发过程中的测试。
首先我们去Apache上下载zookeeper。https://zookeeper.apache.org/
下载下来后解压得到如下文件
打开conf里面的zoo_simple.cfg ,拷贝一份,重新命名为zoo.cfg修改如下地方,适合你自己的环境路径
保存文件。
进入bin目录下,点击启动zkServer.cmd
当出现如下图片的时候。证明zookeeper正常启动,否者不正常启动的话需要检查具体原因,一般是java环境变量没有设置好等问题。
启动好zookeeper之后我们登录zookeeper客户端进行测试。
当列举出节点的时候,我们大概就证明zookeeper能够成功激动了。到此准备工作完成。我们需要将zookeeper整合到Netty游戏服务器中,来实现分布式服务发现和注册的功能。
2:Netty整合zookeeper:实现分布式服务发现和注册
项目模式还是基于上一篇 https://blog.csdn.net/baidu_23086307/article/details/82755939
中的模式。
要向使用zookeeper aip,我们需要在maven工程里面添加zookeeper相关的组件。
1
2
3
4
5
6
7
8
9 1 <dependency>
2 <groupId>org.apache.zookeeper</groupId>
3 <artifactId>zookeeper</artifactId>
4 <version>3.4.9</version>
5
6 </dependency>
7
8
9
上面添加的zookeeper核心组件库。下面是使用apache的curator 用来实现服务动态发现的功能。
所需要添加的库
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 1 <dependency>
2 <groupId>org.apache.curator</groupId>
3 <artifactId>curator-framework</artifactId>
4 <version>RELEASE</version>
5 <scope>compile</scope>
6 </dependency>
7
8 <dependency>
9 <groupId>org.apache.curator</groupId>
10 <artifactId>curator-recipes</artifactId>
11 <version>RELEASE</version>
12 <scope>compile</scope>
13 </dependency>
14
15
相关的环境和jar都准备好之后我们需要添加一个配置文件。来统一配置zookeeper服务器的基本信息。
我们在项目中的resource下添加一个zookeeper.properties文件
内容如下
1
2
3
4
5
6
7
8
9 1zookeeper.timeout=5000
2zookeeper.registry.path=/rpc_registry
3zookeeper.data.path=/data
4zookeeper.port=2181
5zookeeper.ip=0.0.0.0
6# 服务发现时间
7zookeeper.elapsedTimeMs=10000
8
9
一些简单基础的配置。足以说明问题。
首先我们来编写一个读取properties文件的配置类,我们将bean对象丢给spring做管理,所以我们能够轻松的在任何地方使用我们的这个对象。
ZookeeperConfig
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 1package com.twjitm.core.common.config.global;
2
3import org.slf4j.Logger;
4import org.slf4j.LoggerFactory;
5import org.springframework.stereotype.Service;
6
7import java.io.IOException;
8import java.io.InputStream;
9import java.util.Properties;
10
11/**
12 * Created by IntelliJ IDEA.
13 * User: 文江 Date: 2018/8/19 Time: 13:29
14 * https://blog.csdn.net/baidu_23086307
15 */
16@Service
17public class ZookeeperConfig {
18 private final Logger logger = LoggerFactory.getLogger(ZookeeperConfig.class);
19 private int timeOut;
20 private String dataPath;
21 private String registryPath;
22 private int serverPort;
23 private String serverHost;
24
25 private int elapsedTimeMs;
26 private Properties properties;
27
28
29 public void init() {
30 InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(GlobalConstants.ConfigFile.ZOOKEEPER_PROPERTIES_FILE_PATH);
31 try {
32 properties = new Properties();
33 properties.load(in);
34 timeOut = Integer.parseInt(properties.getProperty("zookeeper.timeout"));
35 dataPath = properties.getProperty("zookeeper.data.path");
36 registryPath = properties.getProperty("zookeeper.registry.path");
37 serverPort = Integer.parseInt(properties.getProperty("zookeeper.port"));
38 serverHost = properties.getProperty("zookeeper.ip");
39 elapsedTimeMs = Integer.parseInt(properties.getProperty("zookeeper.elapsedTimeMs"));
40 } catch (IOException e) {
41 e.printStackTrace();
42 logger.error("error", e);
43 }
44 }
45
46 public String getRegistryAddress() {
47 return this.getServerHost() + ":" + this.getServerPort();
48 }
49
50 public String getRegistryPath() {
51 return registryPath;
52 }
53
54 public int getTimeOut() {
55 return timeOut;
56 }
57
58 public int getServerPort() {
59 return serverPort;
60 }
61
62 public void setServerPort(int serverPort) {
63 this.serverPort = serverPort;
64 }
65
66 public String getServerHost() {
67 return serverHost;
68 }
69
70 public int getElapsedTimeMs() {
71 return elapsedTimeMs;
72 }
73
74}
75
76
77
有了这个对象我们能够在应用程序里面对zookeeper发起连接请求,创建节点和更新删除节点请求等一系列的操作。所以这个类对于zookeeper这一模块来说是比较重要的。
2.1:服务注册
当项目启动成功的时候。我们要将本服务器的基础信息告诉zookeeper。通过zookeeper来通知别的服务器。这样就不用去管每台服务器的连接信息,只通过zookeeper获取别的服务器信息。这样有助于管理和动态分配。
服务注册即将服务器节点信息发布到zookeeper中。和zookeeper建立连接关系。
在这个地方我们模拟将要注入三种角色的节点:
1:world服务器
2; game服务器
3:db服务器
所以我们需要一个枚举类来记录每个节点下的根目录
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 1package com.twjitm.core.common.zookeeper;
2
3import com.twjitm.core.common.enums.NettyGameTypeEnum;
4
5/**
6 * @author twjitm - [Created on 2018-08-22 10:42]
7 * zookeeper 节点枚举
8 */
9public enum NettyZookeeperNodeNettyGameTypeEnum {
10 WORLD(NettyGameTypeEnum.WORLD, "/registry_world_address"),
11 GAME(NettyGameTypeEnum.GAME, "/registry_game_address"),
12 DB(NettyGameTypeEnum.DB, "/registry_db_address"),;
13
14 private NettyGameTypeEnum nettyGameTypeEnum;
15 private String rootPath;
16
17
18 NettyZookeeperNodeNettyGameTypeEnum(NettyGameTypeEnum nettyGameTypeEnum, String rootPath) {
19 this.nettyGameTypeEnum = nettyGameTypeEnum;
20 this.rootPath = rootPath;
21 }
22
23 public NettyGameTypeEnum getNettyGameTypeEnum() {
24 return nettyGameTypeEnum;
25 }
26
27 public void setNettyGameTypeEnum(NettyGameTypeEnum nettyGameTypeEnum) {
28 this.nettyGameTypeEnum = nettyGameTypeEnum;
29 }
30
31 public String getRootPath() {
32 return rootPath;
33 }
34
35 public void setRootPath(String rootPath) {
36 this.rootPath = rootPath;
37 }
38}
39
40
41
有了节点枚举类。我们需要将本服务器注入到zookeeper中。下面代码演示了如何将节点注入到zookeeper系统中去。
首先我们要连接到zookeeper,连接通之后我们在注入节点,当节点信息存在的时候我们就不用注册了
当节点信息不存在的时候我们才注入。
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214 1
2package com.twjitm.core.common.zookeeper;
3
4import com.twjitm.core.common.config.global.NettyGameServiceConfig;
5import com.twjitm.core.common.config.global.NettyGameServiceConfigService;
6import com.twjitm.core.common.config.global.ZookeeperConfig;
7import com.twjitm.core.common.config.rpc.RpcServerConfig;
8import com.twjitm.core.common.service.IService;
9import com.twjitm.core.common.service.rpc.server.NettySdRpcServiceProvider;
10import com.twjitm.core.spring.SpringServiceManager;
11import org.apache.zookeeper.CreateMode;
12import org.apache.zookeeper.KeeperException;
13import org.apache.zookeeper.ZooDefs;
14import org.apache.zookeeper.ZooKeeper;
15import org.apache.zookeeper.data.Stat;
16import org.slf4j.Logger;
17import org.slf4j.LoggerFactory;
18import org.springframework.util.StringUtils;
19
20import java.io.IOException;
21import java.util.concurrent.CountDownLatch;
22
23/**
24 * @author twjtim - [Created on 2018-08-22 11:16]
25 * @jdk java version "1.8.0_77"
26 */
27public class NettyZookeeperRpcServiceRegistryService implements IService {
28 private static final Logger logger = LoggerFactory.getLogger(NettyZookeeperRpcServiceRegistryService.class);
29 private CountDownLatch countDownLatch = new CountDownLatch(1);
30 private ZooKeeper zooKeeper;
31
32 @Override
33 public String getId() {
34 return NettyZookeeperRpcServiceRegistryService.class.getSimpleName();
35 }
36
37 @Override
38 public void startup() throws Exception {
39 logger.info("STARTUP ZOOKEEPER SERVER BEGINNING");
40 NettyGameServiceConfigService gameServiceConfigService = SpringServiceManager.getSpringLoadService().getNettyGameServiceConfigService();
41 boolean isOpen = gameServiceConfigService.getNettyGameServiceConfig().isZookeeperOpen();
42 if (isOpen) {
43 registryZookeeper();
44 registryZookeeperNode();
45 }
46
47
48 }
49
50 /**
51 * 在启动服务器的时候,需要将服务器信息注册到zookeeper,提供给其他服务器使用,当服务器不可达时候,zookeeper会将
52 * 服务器信息清楚,达到容灾策略。
53 */
54 private void registryZookeeperNode() {
55 NettyGameServiceConfigService gameConfig = SpringServiceManager.getSpringLoadService().getNettyGameServiceConfigService();
56 RpcServerConfig rpcConfig = gameConfig.getRpcServerConfig();
57 NettyGameServiceConfig gameServiceConfig = gameConfig.getNettyGameServiceConfig();
58 NettySdRpcServiceProvider nettySdRpcServiceProvider = rpcConfig.getProvider();
59 boolean worldOpen = nettySdRpcServiceProvider.isWorldOpen();
60 if (worldOpen) {
61 NettyZookeeperNodeInfo zookeeperNodeInfo = new NettyZookeeperNodeInfo(NettyZookeeperNodeNettyGameTypeEnum.WORLD,
62 gameServiceConfig.getServerId(),
63 gameServiceConfig.getServerHost(),
64 gameServiceConfig.getServerPort());
65 registry(zookeeperNodeInfo);
66 logger.info("注册world节点到zookeeper");
67 }
68 if (nettySdRpcServiceProvider.isGameOpen()) {
69 NettyZookeeperNodeInfo zookeeperNodeInfo = new NettyZookeeperNodeInfo(NettyZookeeperNodeNettyGameTypeEnum.GAME,
70 gameServiceConfig.getServerId(),
71 gameServiceConfig.getServerHost(),
72 gameServiceConfig.getServerPort());
73 registry(zookeeperNodeInfo);
74 logger.info("注册game节点到zookeeper");
75 }
76
77 if (nettySdRpcServiceProvider.isDbOpen()) {
78 NettyZookeeperNodeInfo zookeeperNodeInfo = new NettyZookeeperNodeInfo(NettyZookeeperNodeNettyGameTypeEnum.DB,
79 gameServiceConfig.getServerId(),
80 gameServiceConfig.getServerHost(),
81 gameServiceConfig.getServerPort());
82 registry(zookeeperNodeInfo);
83 logger.info("注册db节点到zookeeper");
84 }
85
86 }
87
88 private void registry(NettyZookeeperNodeInfo zookeeperNodeInfo) {
89 String rootPath = zookeeperNodeInfo.getNettyZookeeperNodeNettyGameTypeEnum().getRootPath();
90 String nodePath = zookeeperNodeInfo.getZookeeperNodePath();
91 String nodeData = null;
92 try {
93 nodeData = zookeeperNodeInfo.serialize();
94 } catch (IOException e) {
95 e.printStackTrace();
96 }
97 if (!StringUtils.isEmpty(rootPath)) {
98 if (zooKeeper != null) {
99 addRootNode(zooKeeper, rootPath);
100 try {
101 if (zooKeeper.exists(nodePath, false) != null) {
102 deleteNode(zooKeeper, nodePath);
103 logger.info("DELETE ZOOKEEPER NODE ", nodeData);
104 }
105 } catch (KeeperException e) {
106 } catch (InterruptedException e) {
107 }
108 createNode(zooKeeper, nodePath, nodeData);
109 logger.info("CREATE ZOOKEEPER NODE " + nodeData);
110 }
111 }
112 }
113
114 private void registryZookeeper() {
115 if (zooKeeper == null) {
116 zooKeeper = connectZookeeperServer();
117 }
118 }
119
120 /**
121 * 链接到zookeeper 服务器
122 *
123 * @return
124 */
125 private ZooKeeper connectZookeeperServer() {
126 ZooKeeper zk = null;
127 try {
128 NettyGameServiceConfigService gameServerConfigService = SpringServiceManager.getSpringLoadService().getNettyGameServiceConfigService();
129 ZookeeperConfig zooKeeperConfig = gameServerConfigService.getZookeeperConfig();
130 String hostAndPort = zooKeeperConfig.getServerHost() + ":" + zooKeeperConfig.getServerPort();
131 zk = new ZooKeeper(hostAndPort, zooKeeperConfig.getTimeOut(),
132 event -> countDownLatch.countDown());
133 } catch (Exception e) {
134 logger.error(e.toString(), e);
135 }
136 return zk;
137 }
138
139 private void addRootNode(ZooKeeper zk, String rootPath) {
140 try {
141 Stat s = zk.exists(rootPath, false);
142 if (s == null) {
143 createRootNode(rootPath, new byte[0]);
144 logger.info("CREATE ZOOKEEPER ROOT NODE " + rootPath);
145 }
146 } catch (Exception e) {
147 logger.error(e.toString(), e);
148 }
149
150 }
151
152 private void createNode(ZooKeeper zk, String nodePath, String nodeData) {
153 try {
154 byte[] bytes = nodeData.getBytes();
155 String path = create(nodePath, bytes);
156 logger.debug("CREATE ZOOKEEPER NODE ({} => {})", path, bytes);
157 } catch (Exception e) {
158 logger.error(e.toString(), e);
159 }
160 }
161
162 /**
163 * <b>function:</b>创建持久态的znode,比支持多层创建.比如在创建/parent/child的情况下,无/parent.无法通过
164 *
165 * @param path
166 * @param data
167 * @throws KeeperException
168 * @throws InterruptedException
169 */
170 public String createRootNode(String path, byte[] data) throws Exception {
171 /**
172 * 此处采用的是CreateMode是PERSISTENT 表示The znode will not be automatically deleted upon client's disconnect.
173 * EPHEMERAL 表示The znode will be deleted upon the client's disconnect.
174 */
175 return this.zooKeeper.create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
176 }
177
178
179 /**
180 * <b>function:</b>创建持久态的znode,比支持多层创建.比如在创建/parent/child的情况下,无/parent.无法通过
181 *
182 * @param path
183 * @param data
184 */
185 public String create(String path, byte[] data) throws Exception {
186 /**
187 * 此处采用的是CreateMode是PERSISTENT 表示The znode will not be automatically deleted upon client's disconnect.
188 * EPHEMERAL 表示The znode will be deleted upon the client's disconnect.
189 */
190 return this.zooKeeper.create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
191 }
192
193
194 public void deleteNode(ZooKeeper zk, String nodePath) {
195 try {
196 zk.delete(nodePath, -1);
197 logger.debug("delete zookeeper node path c ({} => {})", nodePath);
198 } catch (Exception e) {
199 logger.error(e.toString(), e);
200 }
201 }
202
203
204 @Override
205 public void shutdown() throws Exception {
206 if (zooKeeper != null) {
207 zooKeeper.close();
208 }
209
210 }
211}
212
213
214
在项目启动完成的时候我们调用startup方法,既可以注入节点到zookeeper。
2.2:服务发现
想要获取zookeeper关注的节点,我们需要借助Apache 开源的客户端Curator 不知道Curator使用的可以进行再这查看。
https://blog.csdn.net/baidu_23086307/article/details/82745545 更多的还得去看看官方教程。
通过curator这个库,我们能够动态的获取zookeeper的节点信息,当zookeeper节点信息发生改变的时候能够及时通知到关注的节点。
zookeeper服务发现的核心代码
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224 1package com.twjitm.core.common.zookeeper;
2
3import com.twjitm.core.common.config.global.NettyGameServiceConfig;
4import com.twjitm.core.common.config.global.NettyGameServiceConfigService;
5import com.twjitm.core.common.config.global.ZookeeperConfig;
6import com.twjitm.core.common.service.IService;
7import com.twjitm.core.common.service.rpc.service.NettyRpcClientConnectService;
8import com.twjitm.core.spring.SpringServiceManager;
9import org.apache.curator.framework.CuratorFramework;
10import org.apache.curator.framework.CuratorFrameworkFactory;
11import org.apache.curator.framework.api.ACLProvider;
12import org.apache.curator.framework.recipes.cache.ChildData;
13import org.apache.curator.framework.recipes.cache.TreeCache;
14import org.apache.curator.retry.RetryNTimes;
15import org.apache.zookeeper.ZooDefs;
16import org.apache.zookeeper.data.ACL;
17import org.apache.zookeeper.data.Id;
18import org.slf4j.Logger;
19import org.slf4j.LoggerFactory;
20
21import java.util.ArrayList;
22import java.util.List;
23import java.util.concurrent.ConcurrentHashMap;
24
25/**
26 * 采用Apache Curator 来发现zookeeper服务。
27 *
28 * @author twjitm - [Created on 2018-08-22 15:57]
29 * @jdk java version "1.8.0_77"
30 * zookeeper 服务发现
31 */
32
33public class NettyZookeeperRpcServiceDiscoveryService implements IService {
34 private Logger logger = LoggerFactory.getLogger(NettyZookeeperRpcServiceDiscoveryService.class);
35 private volatile ConcurrentHashMap<NettyZookeeperNodeNettyGameTypeEnum, List<NettyZookeeperNodeInfo>> nettyZookeeperNodeMap;
36 /**
37 * zookeeper连接客户端 https://blog.csdn.net/dc_726/article/details/46475633
38 */
39 private CuratorFramework client;
40
41 @Override
42 public String getId() {
43 return NettyZookeeperRpcServiceDiscoveryService.class.getSimpleName();
44 }
45
46 public List<NettyZookeeperNodeInfo> getNodeList(final NettyZookeeperNodeNettyGameTypeEnum zooKeeperNodeBoEnum) {
47 return nettyZookeeperNodeMap.get(zooKeeperNodeBoEnum);
48 }
49
50 @Override
51 public void startup() throws Exception {
52 nettyZookeeperNodeMap = new ConcurrentHashMap<>();
53 NettyGameServiceConfigService gameConfig = SpringServiceManager.getSpringLoadService().getNettyGameServiceConfigService();
54 NettyGameServiceConfig gameServiceConfig = gameConfig.getNettyGameServiceConfig();
55 boolean openZookeeper = gameServiceConfig.isZookeeperOpen();
56 //创建一个连接
57 if (openZookeeper) {
58 try {
59 client = createCuratorClient();
60 } catch (Exception e) {
61 logger.error("ERROR IN NettyZookeeperRpcServiceDiscoveryService startup()", e);
62 }
63
64 NettyZookeeperNodeNettyGameTypeEnum[] nodeNettyGameTypeEnum = NettyZookeeperNodeNettyGameTypeEnum.values();
65 for (NettyZookeeperNodeNettyGameTypeEnum temp : nodeNettyGameTypeEnum) {
66 discoveryService(temp);
67 }
68
69 }
70
71 }
72
73
74 private void discoveryService(NettyZookeeperNodeNettyGameTypeEnum nettyZookeeperNodeNettyGameTypeEnum) {
75 if (client == null) {
76 client = createCuratorClient();
77 }
78 try {
79 setCuratorListener(client, nettyZookeeperNodeNettyGameTypeEnum);
80 } catch (Exception e) {
81 if (logger.isDebugEnabled()) {
82 logger.debug("CURATORFRAMEWORK LISTENING EXCEPTION:" + e.getMessage());
83 }
84 }
85 }
86
87 /**
88 * 设置一个监听器,负责监听zookeeper信息变化回调
89 * Apache Curator
90 *
91 * @param client
92 * @param nettyZookeeperNodeNettyGameTypeEnum
93 */
94 private void setCuratorListener(CuratorFramework client, NettyZookeeperNodeNettyGameTypeEnum nettyZookeeperNodeNettyGameTypeEnum) throws Exception {
95
96 List<String> childRenList = client.getChildren().forPath(nettyZookeeperNodeNettyGameTypeEnum.getRootPath());
97 List<NettyZookeeperNodeInfo> tempNodeList = new ArrayList<>();
98 for (String node : childRenList) {
99 NettyZookeeperNodeInfo zooKeeperNodeInfo = new NettyZookeeperNodeInfo();
100 byte[] bytes = client.getData().forPath(nettyZookeeperNodeNettyGameTypeEnum.getRootPath() + "/" + node);
101 if (bytes != null) {
102 zooKeeperNodeInfo.deserialize(new String(bytes));
103 tempNodeList.add(zooKeeperNodeInfo);
104 }
105 }
106
107 if (logger.isDebugEnabled()) {
108 logger.debug("NODE DATA: {}", tempNodeList);
109 }
110
111 nettyZookeeperNodeMap.put(nettyZookeeperNodeNettyGameTypeEnum, tempNodeList);
112 if (logger.isDebugEnabled()) {
113 logger.debug("SERVICE DISCOVERY TRIGGERED UPDATING CONNECTED SERVER NODE.");
114 }
115
116 NettyRpcClientConnectService rpcClientConnectService = SpringServiceManager.getSpringLoadService().getNettyRpcClientConnectService();
117 rpcClientConnectService.notifyConnect(nettyZookeeperNodeNettyGameTypeEnum, nettyZookeeperNodeMap.get(nettyZookeeperNodeNettyGameTypeEnum));
118
119 TreeCache cache = new TreeCache(client, nettyZookeeperNodeNettyGameTypeEnum.getRootPath());
120 cache.getListenable().addListener((client1, event) -> {
121 ChildData data = event.getData();
122 if (data != null) {
123 switch (event.getType()) {
124 case NODE_ADDED:
125 if (logger.isDebugEnabled()) {
126 logger.debug("NODE_ADDED : " + data.getPath() + " DATA:" + new String(data.getData()));
127 }
128 break;
129 case NODE_REMOVED:
130 if (logger.isDebugEnabled()) {
131 logger.debug("NODE_REMOVED : " + data.getPath() + " DATA:" + new String(data.getData()));
132 }
133 break;
134 case NODE_UPDATED:
135 if (logger.isDebugEnabled()) {
136 logger.debug("NODE_UPDATED : " + data.getPath() + " DATA:" + new String(data.getData()));
137 }
138 break;
139 default:
140 break;
141 }
142 } else {
143 switch (event.getType()) {
144 case CONNECTION_SUSPENDED:
145 if (logger.isDebugEnabled()) {
146 logger.debug("DATA IS NULL : " + "CONNECTION_SUSPENDED");
147 }
148 break;
149 case CONNECTION_RECONNECTED:
150 if (logger.isDebugEnabled()) {
151 logger.debug("DATA IS NULL : " + "CONNECTION_RECONNECTED");
152 }
153 break;
154 case CONNECTION_LOST:
155 if (logger.isDebugEnabled()) {
156 logger.debug("DATA IS NULL : " + "CONNECTION_LOST");
157 }
158 break;
159 default:
160 break;
161 }
162 }
163 });
164 // 开始监听
165 cache.start();
166 }
167
168
169 private CuratorFramework createCuratorClient() {
170 /**
171 * ACL 提供者
172 */
173 ACLProvider aclProvider = new ACLProvider() {
174 private List<ACL> acl;
175
176 @Override
177 public List<ACL> getDefaultAcl() {
178 if (acl == null) {
179 ArrayList<ACL> acl = ZooDefs.Ids.CREATOR_ALL_ACL;
180 acl.clear();
181 acl.add(new ACL(ZooDefs.Perms.ALL, new Id("auth", "admin:admin")));
182 this.acl = acl;
183 }
184 return acl;
185 }
186
187 @Override
188 public List<ACL> getAclForPath(String path) {
189 return acl;
190 }
191 };
192
193
194 int connectionTimeoutMs = SpringServiceManager.getSpringLoadService().getNettyGameServiceConfigService().getZookeeperConfig().getTimeOut();
195 NettyGameServiceConfigService gameServerConfigService = SpringServiceManager.getSpringLoadService().getNettyGameServiceConfigService();
196 ZookeeperConfig zooKeeperConfig = gameServerConfigService.getZookeeperConfig();
197 String registryAddress = zooKeeperConfig.getRegistryAddress();
198
199 CuratorFramework client = CuratorFrameworkFactory.builder()
200 .aclProvider(aclProvider)
201 .connectionTimeoutMs(connectionTimeoutMs)
202 .connectString(registryAddress)
203 .retryPolicy(
204 new RetryNTimes(Integer.MAX_VALUE, zooKeeperConfig.getElapsedTimeMs())
205 ).build();//绑定
206 //启动
207 client.start();
208 return client;
209 }
210
211 @Override
212 public void shutdown() throws Exception {
213 if (client != null) {
214 try {
215 client.close();
216 } catch (Exception e) {
217 logger.error(e.toString(), e);
218 }
219 }
220 }
221}
222
223
224
定时检测zookeeper上的节点是否发生改变,若是发生改变了需要刷新本地缓存的服务器上的列表。
最后我们来测试一下zookeeper分布式服务发现和注册
编写一个测试类来测试一下:
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 1package com.twjitm.rpc.zookeeper;
2
3import com.twjitm.TestSpring;
4import com.twjitm.core.bootstrap.Bootstrap;
5import com.twjitm.core.common.zookeeper.NettyZookeeperNodeInfo;
6import com.twjitm.core.common.zookeeper.NettyZookeeperNodeNettyGameTypeEnum;
7import com.twjitm.core.common.zookeeper.NettyZookeeperRpcServiceDiscoveryService;
8import com.twjitm.core.common.zookeeper.NettyZookeeperRpcServiceRegistryService;
9import com.twjitm.core.spring.SpringServiceManager;
10
11import java.util.List;
12
13/**
14 * @author twjtim - [Created on 2018-08-23 11:48]
15
16 */
17public class NettyZookeeperTest {
18 private static NettyZookeeperRpcServiceRegistryService registryService;
19 private static NettyZookeeperRpcServiceDiscoveryService discoveryService;
20
21 public static void main(String[] args) {
22 TestSpring.initSpring();
23 Bootstrap.startServer();
24 registryService = SpringServiceManager.getSpringLoadService().getNettyZookeeperRpcServiceRegistryService();
25 discoveryService = SpringServiceManager.getSpringLoadService().getNettyZookeeperRpcServiceDiscoveryService();
26 test();
27
28 }
29
30 private static void test() {
31 List<NettyZookeeperNodeInfo> list = discoveryService.getNodeList(NettyZookeeperNodeNettyGameTypeEnum.WORLD);
32 System.out.println(list);
33 }
34}
35
36
37
运行效果:
能够将本地的服务器信息注册到zookeeper服务器上,也能够获取到zookeeper服务器上已经注入的别的服务器信息。
因此我们使用zookeeper实现一个分布式服务发现和注册相对来说是一个简单高效的方式,特别实在游戏服务器架构方面来说简直是一大福利,我们少去了许多服务器配置,而且要是服务器宕机,客户端服务器没有办法及时检测到。所以zookeeper的使用能够帮助我们解决不少问题。