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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baidu_23086307/article/details/82769234

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相关的组件。

 <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.9</version>

        </dependency>

上面添加的zookeeper核心组件库。下面是使用apache的curator 用来实现服务动态发现的功能。

所需要添加的库

  <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>

相关的环境和jar都准备好之后我们需要添加一个配置文件。来统一配置zookeeper服务器的基本信息。

我们在项目中的resource下添加一个zookeeper.properties文件
内容如下

zookeeper.timeout=5000
zookeeper.registry.path=/rpc_registry
zookeeper.data.path=/data
zookeeper.port=2181
zookeeper.ip=0.0.0.0
# 服务发现时间
zookeeper.elapsedTimeMs=10000

一些简单基础的配置。足以说明问题。
首先我们来编写一个读取properties文件的配置类,我们将bean对象丢给spring做管理,所以我们能够轻松的在任何地方使用我们的这个对象。

ZookeeperConfig

package com.twjitm.core.common.config.global;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * Created by IntelliJ IDEA.
 * User: 文江 Date: 2018/8/19  Time: 13:29
 * https://blog.csdn.net/baidu_23086307
 */
@Service
public class ZookeeperConfig {
    private final Logger logger = LoggerFactory.getLogger(ZookeeperConfig.class);
    private int timeOut;
    private String dataPath;
    private String registryPath;
    private int serverPort;
    private String serverHost;

    private int elapsedTimeMs;
    private Properties properties;


    public void init() {
        InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(GlobalConstants.ConfigFile.ZOOKEEPER_PROPERTIES_FILE_PATH);
        try {
            properties = new Properties();
            properties.load(in);
            timeOut = Integer.parseInt(properties.getProperty("zookeeper.timeout"));
            dataPath = properties.getProperty("zookeeper.data.path");
            registryPath = properties.getProperty("zookeeper.registry.path");
            serverPort = Integer.parseInt(properties.getProperty("zookeeper.port"));
            serverHost = properties.getProperty("zookeeper.ip");
            elapsedTimeMs = Integer.parseInt(properties.getProperty("zookeeper.elapsedTimeMs"));
        } catch (IOException e) {
            e.printStackTrace();
            logger.error("error", e);
        }
    }

    public String getRegistryAddress() {
        return this.getServerHost() + ":" + this.getServerPort();
    }

    public String getRegistryPath() {
        return registryPath;
    }

    public int getTimeOut() {
        return timeOut;
    }

    public int getServerPort() {
        return serverPort;
    }

    public void setServerPort(int serverPort) {
        this.serverPort = serverPort;
    }

    public String getServerHost() {
        return serverHost;
    }

    public int getElapsedTimeMs() {
        return elapsedTimeMs;
    }

}

有了这个对象我们能够在应用程序里面对zookeeper发起连接请求,创建节点和更新删除节点请求等一系列的操作。所以这个类对于zookeeper这一模块来说是比较重要的。
2.1:服务注册
当项目启动成功的时候。我们要将本服务器的基础信息告诉zookeeper。通过zookeeper来通知别的服务器。这样就不用去管每台服务器的连接信息,只通过zookeeper获取别的服务器信息。这样有助于管理和动态分配。

服务注册即将服务器节点信息发布到zookeeper中。和zookeeper建立连接关系。
在这个地方我们模拟将要注入三种角色的节点:
1:world服务器
2; game服务器
3:db服务器
所以我们需要一个枚举类来记录每个节点下的根目录

package com.twjitm.core.common.zookeeper;

import com.twjitm.core.common.enums.NettyGameTypeEnum;

/**
 * @author twjitm - [Created on 2018-08-22 10:42]
 * zookeeper 节点枚举
 */
public enum NettyZookeeperNodeNettyGameTypeEnum {
    WORLD(NettyGameTypeEnum.WORLD, "/registry_world_address"),
    GAME(NettyGameTypeEnum.GAME, "/registry_game_address"),
    DB(NettyGameTypeEnum.DB, "/registry_db_address"),;

    private NettyGameTypeEnum nettyGameTypeEnum;
    private String rootPath;


    NettyZookeeperNodeNettyGameTypeEnum(NettyGameTypeEnum nettyGameTypeEnum, String rootPath) {
        this.nettyGameTypeEnum = nettyGameTypeEnum;
        this.rootPath = rootPath;
    }

    public NettyGameTypeEnum getNettyGameTypeEnum() {
        return nettyGameTypeEnum;
    }

    public void setNettyGameTypeEnum(NettyGameTypeEnum nettyGameTypeEnum) {
        this.nettyGameTypeEnum = nettyGameTypeEnum;
    }

    public String getRootPath() {
        return rootPath;
    }

    public void setRootPath(String rootPath) {
        this.rootPath = rootPath;
    }
}

有了节点枚举类。我们需要将本服务器注入到zookeeper中。下面代码演示了如何将节点注入到zookeeper系统中去。
首先我们要连接到zookeeper,连接通之后我们在注入节点,当节点信息存在的时候我们就不用注册了
当节点信息不存在的时候我们才注入。


package com.twjitm.core.common.zookeeper;

import com.twjitm.core.common.config.global.NettyGameServiceConfig;
import com.twjitm.core.common.config.global.NettyGameServiceConfigService;
import com.twjitm.core.common.config.global.ZookeeperConfig;
import com.twjitm.core.common.config.rpc.RpcServerConfig;
import com.twjitm.core.common.service.IService;
import com.twjitm.core.common.service.rpc.server.NettySdRpcServiceProvider;
import com.twjitm.core.spring.SpringServiceManager;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;

/**
 * @author twjtim - [Created on 2018-08-22 11:16]
 * @jdk java version "1.8.0_77"
 */
public class NettyZookeeperRpcServiceRegistryService implements IService {
    private static final Logger logger = LoggerFactory.getLogger(NettyZookeeperRpcServiceRegistryService.class);
    private CountDownLatch countDownLatch = new CountDownLatch(1);
    private ZooKeeper zooKeeper;

    @Override
    public String getId() {
        return NettyZookeeperRpcServiceRegistryService.class.getSimpleName();
    }

    @Override
    public void startup() throws Exception {
        logger.info("STARTUP ZOOKEEPER SERVER BEGINNING");
        NettyGameServiceConfigService gameServiceConfigService = SpringServiceManager.getSpringLoadService().getNettyGameServiceConfigService();
        boolean isOpen = gameServiceConfigService.getNettyGameServiceConfig().isZookeeperOpen();
        if (isOpen) {
            registryZookeeper();
            registryZookeeperNode();
        }


    }

    /**
     * 在启动服务器的时候,需要将服务器信息注册到zookeeper,提供给其他服务器使用,当服务器不可达时候,zookeeper会将
     * 服务器信息清楚,达到容灾策略。
     */
    private void registryZookeeperNode() {
        NettyGameServiceConfigService gameConfig = SpringServiceManager.getSpringLoadService().getNettyGameServiceConfigService();
        RpcServerConfig rpcConfig = gameConfig.getRpcServerConfig();
        NettyGameServiceConfig gameServiceConfig = gameConfig.getNettyGameServiceConfig();
        NettySdRpcServiceProvider nettySdRpcServiceProvider = rpcConfig.getProvider();
        boolean worldOpen = nettySdRpcServiceProvider.isWorldOpen();
        if (worldOpen) {
            NettyZookeeperNodeInfo zookeeperNodeInfo = new NettyZookeeperNodeInfo(NettyZookeeperNodeNettyGameTypeEnum.WORLD,
                    gameServiceConfig.getServerId(),
                    gameServiceConfig.getServerHost(),
                    gameServiceConfig.getServerPort());
            registry(zookeeperNodeInfo);
            logger.info("注册world节点到zookeeper");
        }
        if (nettySdRpcServiceProvider.isGameOpen()) {
            NettyZookeeperNodeInfo zookeeperNodeInfo = new NettyZookeeperNodeInfo(NettyZookeeperNodeNettyGameTypeEnum.GAME,
                    gameServiceConfig.getServerId(),
                    gameServiceConfig.getServerHost(),
                    gameServiceConfig.getServerPort());
            registry(zookeeperNodeInfo);
            logger.info("注册game节点到zookeeper");
        }

        if (nettySdRpcServiceProvider.isDbOpen()) {
            NettyZookeeperNodeInfo zookeeperNodeInfo = new NettyZookeeperNodeInfo(NettyZookeeperNodeNettyGameTypeEnum.DB,
                    gameServiceConfig.getServerId(),
                    gameServiceConfig.getServerHost(),
                    gameServiceConfig.getServerPort());
            registry(zookeeperNodeInfo);
            logger.info("注册db节点到zookeeper");
        }

    }

    private void registry(NettyZookeeperNodeInfo zookeeperNodeInfo) {
        String rootPath = zookeeperNodeInfo.getNettyZookeeperNodeNettyGameTypeEnum().getRootPath();
        String nodePath = zookeeperNodeInfo.getZookeeperNodePath();
        String nodeData = null;
        try {
            nodeData = zookeeperNodeInfo.serialize();
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (!StringUtils.isEmpty(rootPath)) {
            if (zooKeeper != null) {
                addRootNode(zooKeeper, rootPath);
                try {
                    if (zooKeeper.exists(nodePath, false) != null) {
                        deleteNode(zooKeeper, nodePath);
                        logger.info("DELETE ZOOKEEPER NODE ", nodeData);
                    }
                } catch (KeeperException e) {
                } catch (InterruptedException e) {
                }
                createNode(zooKeeper, nodePath, nodeData);
                logger.info("CREATE ZOOKEEPER NODE " + nodeData);
            }
        }
    }

    private void registryZookeeper() {
        if (zooKeeper == null) {
            zooKeeper = connectZookeeperServer();
        }
    }

    /**
     * 链接到zookeeper 服务器
     *
     * @return
     */
    private ZooKeeper connectZookeeperServer() {
        ZooKeeper zk = null;
        try {
            NettyGameServiceConfigService gameServerConfigService = SpringServiceManager.getSpringLoadService().getNettyGameServiceConfigService();
            ZookeeperConfig zooKeeperConfig = gameServerConfigService.getZookeeperConfig();
            String hostAndPort = zooKeeperConfig.getServerHost() + ":" + zooKeeperConfig.getServerPort();
            zk = new ZooKeeper(hostAndPort, zooKeeperConfig.getTimeOut(),
                    event -> countDownLatch.countDown());
        } catch (Exception e) {
            logger.error(e.toString(), e);
        }
        return zk;
    }

    private void addRootNode(ZooKeeper zk, String rootPath) {
        try {
            Stat s = zk.exists(rootPath, false);
            if (s == null) {
                createRootNode(rootPath, new byte[0]);
                logger.info("CREATE ZOOKEEPER ROOT NODE " + rootPath);
            }
        } catch (Exception e) {
            logger.error(e.toString(), e);
        }

    }

    private void createNode(ZooKeeper zk, String nodePath, String nodeData) {
        try {
            byte[] bytes = nodeData.getBytes();
            String path = create(nodePath, bytes);
            logger.debug("CREATE ZOOKEEPER NODE ({} => {})", path, bytes);
        } catch (Exception e) {
            logger.error(e.toString(), e);
        }
    }

    /**
     * <b>function:</b>创建持久态的znode,比支持多层创建.比如在创建/parent/child的情况下,无/parent.无法通过
     *
     * @param path
     * @param data
     * @throws KeeperException
     * @throws InterruptedException
     */
    public String createRootNode(String path, byte[] data) throws Exception {
        /**
         * 此处采用的是CreateMode是PERSISTENT  表示The znode will not be automatically deleted upon client's disconnect.
         * EPHEMERAL 表示The znode will be deleted upon the client's disconnect.
         */
        return this.zooKeeper.create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    }


    /**
     * <b>function:</b>创建持久态的znode,比支持多层创建.比如在创建/parent/child的情况下,无/parent.无法通过
     *
     * @param path
     * @param data
     */
    public String create(String path, byte[] data) throws Exception {
        /**
         * 此处采用的是CreateMode是PERSISTENT  表示The znode will not be automatically deleted upon client's disconnect.
         * EPHEMERAL 表示The znode will be deleted upon the client's disconnect.
         */
        return this.zooKeeper.create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
    }


    public void deleteNode(ZooKeeper zk, String nodePath) {
        try {
            zk.delete(nodePath, -1);
            logger.debug("delete zookeeper node path c ({} => {})", nodePath);
        } catch (Exception e) {
            logger.error(e.toString(), e);
        }
    }


    @Override
    public void shutdown() throws Exception {
        if (zooKeeper != null) {
            zooKeeper.close();
        }

    }
}

在项目启动完成的时候我们调用startup方法,既可以注入节点到zookeeper。

2.2:服务发现
想要获取zookeeper关注的节点,我们需要借助Apache 开源的客户端Curator 不知道Curator使用的可以进行再这查看。
https://blog.csdn.net/baidu_23086307/article/details/82745545 更多的还得去看看官方教程。

通过curator这个库,我们能够动态的获取zookeeper的节点信息,当zookeeper节点信息发生改变的时候能够及时通知到关注的节点。

zookeeper服务发现的核心代码

package com.twjitm.core.common.zookeeper;

import com.twjitm.core.common.config.global.NettyGameServiceConfig;
import com.twjitm.core.common.config.global.NettyGameServiceConfigService;
import com.twjitm.core.common.config.global.ZookeeperConfig;
import com.twjitm.core.common.service.IService;
import com.twjitm.core.common.service.rpc.service.NettyRpcClientConnectService;
import com.twjitm.core.spring.SpringServiceManager;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.ACLProvider;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.TreeCache;
import org.apache.curator.retry.RetryNTimes;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Id;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 采用Apache Curator 来发现zookeeper服务。
 *
 * @author twjitm - [Created on 2018-08-22 15:57]
 * @jdk java version "1.8.0_77"
 * zookeeper 服务发现
 */

public class NettyZookeeperRpcServiceDiscoveryService implements IService {
    private Logger logger = LoggerFactory.getLogger(NettyZookeeperRpcServiceDiscoveryService.class);
    private volatile ConcurrentHashMap<NettyZookeeperNodeNettyGameTypeEnum, List<NettyZookeeperNodeInfo>> nettyZookeeperNodeMap;
    /**
     * zookeeper连接客户端   https://blog.csdn.net/dc_726/article/details/46475633
     */
    private CuratorFramework client;

    @Override
    public String getId() {
        return NettyZookeeperRpcServiceDiscoveryService.class.getSimpleName();
    }

    public List<NettyZookeeperNodeInfo> getNodeList(final NettyZookeeperNodeNettyGameTypeEnum zooKeeperNodeBoEnum) {
        return nettyZookeeperNodeMap.get(zooKeeperNodeBoEnum);
    }

    @Override
    public void startup() throws Exception {
        nettyZookeeperNodeMap = new ConcurrentHashMap<>();
        NettyGameServiceConfigService gameConfig = SpringServiceManager.getSpringLoadService().getNettyGameServiceConfigService();
        NettyGameServiceConfig gameServiceConfig = gameConfig.getNettyGameServiceConfig();
        boolean openZookeeper = gameServiceConfig.isZookeeperOpen();
        //创建一个连接
        if (openZookeeper) {
            try {
                client = createCuratorClient();
            } catch (Exception e) {
                logger.error("ERROR IN NettyZookeeperRpcServiceDiscoveryService startup()", e);
            }

            NettyZookeeperNodeNettyGameTypeEnum[] nodeNettyGameTypeEnum = NettyZookeeperNodeNettyGameTypeEnum.values();
            for (NettyZookeeperNodeNettyGameTypeEnum temp : nodeNettyGameTypeEnum) {
                discoveryService(temp);
            }

        }

    }


    private void discoveryService(NettyZookeeperNodeNettyGameTypeEnum nettyZookeeperNodeNettyGameTypeEnum) {
        if (client == null) {
            client = createCuratorClient();
        }
        try {
            setCuratorListener(client, nettyZookeeperNodeNettyGameTypeEnum);
        } catch (Exception e) {
            if (logger.isDebugEnabled()) {
                logger.debug("CURATORFRAMEWORK LISTENING EXCEPTION:" + e.getMessage());
            }
        }
    }

    /**
     * 设置一个监听器,负责监听zookeeper信息变化回调
     * Apache Curator
     *
     * @param client
     * @param nettyZookeeperNodeNettyGameTypeEnum
     */
    private void setCuratorListener(CuratorFramework client, NettyZookeeperNodeNettyGameTypeEnum nettyZookeeperNodeNettyGameTypeEnum) throws Exception {

        List<String> childRenList = client.getChildren().forPath(nettyZookeeperNodeNettyGameTypeEnum.getRootPath());
        List<NettyZookeeperNodeInfo> tempNodeList = new ArrayList<>();
        for (String node : childRenList) {
            NettyZookeeperNodeInfo zooKeeperNodeInfo = new NettyZookeeperNodeInfo();
            byte[] bytes = client.getData().forPath(nettyZookeeperNodeNettyGameTypeEnum.getRootPath() + "/" + node);
            if (bytes != null) {
                zooKeeperNodeInfo.deserialize(new String(bytes));
                tempNodeList.add(zooKeeperNodeInfo);
            }
        }

        if (logger.isDebugEnabled()) {
            logger.debug("NODE DATA: {}", tempNodeList);
        }

        nettyZookeeperNodeMap.put(nettyZookeeperNodeNettyGameTypeEnum, tempNodeList);
        if (logger.isDebugEnabled()) {
            logger.debug("SERVICE DISCOVERY TRIGGERED UPDATING CONNECTED SERVER NODE.");
        }

        NettyRpcClientConnectService rpcClientConnectService = SpringServiceManager.getSpringLoadService().getNettyRpcClientConnectService();
        rpcClientConnectService.notifyConnect(nettyZookeeperNodeNettyGameTypeEnum, nettyZookeeperNodeMap.get(nettyZookeeperNodeNettyGameTypeEnum));

        TreeCache cache = new TreeCache(client, nettyZookeeperNodeNettyGameTypeEnum.getRootPath());
        cache.getListenable().addListener((client1, event) -> {
            ChildData data = event.getData();
            if (data != null) {
                switch (event.getType()) {
                    case NODE_ADDED:
                        if (logger.isDebugEnabled()) {
                            logger.debug("NODE_ADDED : " + data.getPath() + "  DATA:" + new String(data.getData()));
                        }
                        break;
                    case NODE_REMOVED:
                        if (logger.isDebugEnabled()) {
                            logger.debug("NODE_REMOVED : " + data.getPath() + "  DATA:" + new String(data.getData()));
                        }
                        break;
                    case NODE_UPDATED:
                        if (logger.isDebugEnabled()) {
                            logger.debug("NODE_UPDATED : " + data.getPath() + "  DATA:" + new String(data.getData()));
                        }
                        break;
                    default:
                        break;
                }
            } else {
                switch (event.getType()) {
                    case CONNECTION_SUSPENDED:
                        if (logger.isDebugEnabled()) {
                            logger.debug("DATA IS NULL : " + "CONNECTION_SUSPENDED");
                        }
                        break;
                    case CONNECTION_RECONNECTED:
                        if (logger.isDebugEnabled()) {
                            logger.debug("DATA IS NULL : " + "CONNECTION_RECONNECTED");
                        }
                        break;
                    case CONNECTION_LOST:
                        if (logger.isDebugEnabled()) {
                            logger.debug("DATA IS NULL : " + "CONNECTION_LOST");
                        }
                        break;
                    default:
                        break;
                }
            }
        });
        // 开始监听
        cache.start();
    }


    private CuratorFramework createCuratorClient() {
        /**
         * ACL 提供者
         */
        ACLProvider aclProvider = new ACLProvider() {
            private List<ACL> acl;

            @Override
            public List<ACL> getDefaultAcl() {
                if (acl == null) {
                    ArrayList<ACL> acl = ZooDefs.Ids.CREATOR_ALL_ACL;
                    acl.clear();
                    acl.add(new ACL(ZooDefs.Perms.ALL, new Id("auth", "admin:admin")));
                    this.acl = acl;
                }
                return acl;
            }

            @Override
            public List<ACL> getAclForPath(String path) {
                return acl;
            }
        };


        int connectionTimeoutMs = SpringServiceManager.getSpringLoadService().getNettyGameServiceConfigService().getZookeeperConfig().getTimeOut();
        NettyGameServiceConfigService gameServerConfigService = SpringServiceManager.getSpringLoadService().getNettyGameServiceConfigService();
        ZookeeperConfig zooKeeperConfig = gameServerConfigService.getZookeeperConfig();
        String registryAddress = zooKeeperConfig.getRegistryAddress();

        CuratorFramework client = CuratorFrameworkFactory.builder()
                .aclProvider(aclProvider)
                .connectionTimeoutMs(connectionTimeoutMs)
                .connectString(registryAddress)
                .retryPolicy(
                        new RetryNTimes(Integer.MAX_VALUE, zooKeeperConfig.getElapsedTimeMs())
                ).build();//绑定
        //启动
        client.start();
        return client;
    }

    @Override
    public void shutdown() throws Exception {
        if (client != null) {
            try {
                client.close();
            } catch (Exception e) {
                logger.error(e.toString(), e);
            }
        }
    }
}

定时检测zookeeper上的节点是否发生改变,若是发生改变了需要刷新本地缓存的服务器上的列表。
在这里插入图片描述

最后我们来测试一下zookeeper分布式服务发现和注册
编写一个测试类来测试一下:

package com.twjitm.rpc.zookeeper;

import com.twjitm.TestSpring;
import com.twjitm.core.bootstrap.Bootstrap;
import com.twjitm.core.common.zookeeper.NettyZookeeperNodeInfo;
import com.twjitm.core.common.zookeeper.NettyZookeeperNodeNettyGameTypeEnum;
import com.twjitm.core.common.zookeeper.NettyZookeeperRpcServiceDiscoveryService;
import com.twjitm.core.common.zookeeper.NettyZookeeperRpcServiceRegistryService;
import com.twjitm.core.spring.SpringServiceManager;

import java.util.List;

/**
 * @author twjtim - [Created on 2018-08-23 11:48]

 */
public class NettyZookeeperTest {
    private static NettyZookeeperRpcServiceRegistryService registryService;
    private static NettyZookeeperRpcServiceDiscoveryService discoveryService;

    public static void main(String[] args) {
        TestSpring.initSpring();
        Bootstrap.startServer();
        registryService = SpringServiceManager.getSpringLoadService().getNettyZookeeperRpcServiceRegistryService();
        discoveryService = SpringServiceManager.getSpringLoadService().getNettyZookeeperRpcServiceDiscoveryService();
       test();

    }

    private static void test() {
        List<NettyZookeeperNodeInfo> list = discoveryService.getNodeList(NettyZookeeperNodeNettyGameTypeEnum.WORLD);
        System.out.println(list);
    }
}

运行效果:

在这里插入图片描述

能够将本地的服务器信息注册到zookeeper服务器上,也能够获取到zookeeper服务器上已经注入的别的服务器信息。
因此我们使用zookeeper实现一个分布式服务发现和注册相对来说是一个简单高效的方式,特别实在游戏服务器架构方面来说简直是一大福利,我们少去了许多服务器配置,而且要是服务器宕机,客户端服务器没有办法及时检测到。所以zookeeper的使用能够帮助我们解决不少问题。

阅读更多

扫码向博主提问

twjitm

博客专家

非学,无以致疑;非问,无以广识
  • 擅长领域:
  • java
  • spring
  • mybatis
  • hibernate
  • javaweb
去开通我的Chat快问
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页