Netty游戏服务器实战开发(6):Netty整合Zookeeper实现分布式服务发现与注册

释放双眼,带上耳机,听听看~!

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的使用能够帮助我们解决不少问题。

给TA打赏
共{{data.count}}人
人已打赏
安全网络

CDN安全市场到2022年价值76.3亿美元

2018-2-1 18:02:50

安全经验

Skipfish 2.04b 发布,Web应用安全检测

2012-2-26 11:12:22

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索