美文网首页RPCzookeeper分布式
分布式--安装zookeeper、结合RMI实现RPC框架

分布式--安装zookeeper、结合RMI实现RPC框架

作者: aruba | 来源:发表于2022-06-16 10:48 被阅读0次

    对于后端大型项目开发,都会将功能模块拆分并部署在不同服务器上,那么不同模块之间的跨网络通讯是必不可少的,RPC协议就由此诞生,广义上的RPC就是跨网络通讯,具体的框架如Dubbo。从架构来说,RPC一般都带有注册中心,对客户端和服务端进行管理,服务端在注册中心提供对外接口,客户端获取服务端接口调用,实现跨网络通讯

    一、zookeeper安装

    zookeeper是分布式管理软件,一般作为RPC通讯的注册中心

    1. 下载zookeeper

    官网下载地址:https://zookeeper.apache.org/releases.html#download

    下载稳定版本:

    2. 传输到服务器中

    我这边利用sftp,上传服务器中:

    sftp> put ./apache-zookeeper-3.7.1-bin.tar.gz /root
    

    3. 解压

    tar zxf apache-zookeeper-3.7.1-bin.tar.gz
    mv apache-zookeeper-3.7.1-bin zookeeper
    

    4. 创建data文件夹

    zookeeper需要一个路径用于存放服务端的注册信息

    cd zookeeper
    mkdir data
    

    在配置文件中指定该路径

    cd conf
    mv zoo-simple.cfg zoo.cfg
    vi zoo.cfg
    

    修改配置文件内容:

    dataDir = /root/zookeeper/data
    

    5. 启动zookeeper

    在bin目录下执行shell脚本:

    cd /root/zookeeper/bin
    ./zkServer.sh start
    

    查看zookeeper状态可以执行:

    ./zkServer.sh status
    

    关闭防火墙:

    systemctl stop firewalld
    

    二、使用zookeeper

    1. 导入依赖

    新建Maven项目,导入依赖:

            <!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
            <dependency>
                <groupId>org.apache.zookeeper</groupId>
                <artifactId>zookeeper</artifactId>
                <version>3.7.1</version>
            </dependency>
            <!--junit-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.13.1</version>
                <scope>test</scope>
            </dependency>
    

    2. 使用zookeeper注册内容

    编写一个test方法:

        @Test
        public void register() throws IOException, InterruptedException, KeeperException {
            // 获取zooKeeper对象
            ZooKeeper zooKeeper = new ZooKeeper("192.168.42.4:2181", 10000, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
                    System.out.println("连接成功");
                }
            });
    
    
            //ZooDefs.Ids.OPEN_ACL_UNSAFE 表示权限。
            //CreateMode.PERSISTENT_SEQUENTIAL 永久存储,文件内容编号递增。
            String info = zooKeeper.create("/demos", "hello".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
            System.out.println("info:" + info);
        }
    

    执行结果:

    连接成功
    info:/demos0000000001

    3. 获取zookeeper中的内容

    编写test方法:

        @Test
        public void read() throws IOException, InterruptedException, KeeperException {
            // 获取zooKeeper对象
            ZooKeeper zooKeeper = new ZooKeeper("192.168.42.4:2181", 10000, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
                    System.out.println("连接成功");
                }
            });
    
            byte[] data = zooKeeper.getData("/demos0000000001", false, null);
            System.out.println(new String(data));
        }
    

    结果:

    连接成功
    hello

    三、RMI使用

    RMI是JDK提供的远程方法调用工具,一个Java程序可以像调用本地方法一样调用另一个Java程序的内容,不支持跨语言
    RMI使用流程大致分为两步,第一,它拥有注册表,用于存放服务端对象,服务端通过bind方法注册该对象;第二,客户端通过lookup方法从注册表中获取服务端对象。和安卓Binder机制挺像,客户端也要有一份服务端对象的类

    1. 编写服务端

    创建一个maven的Module,作为RMI服务端项目

    1.1 定义对外接口

    要求:继承至Remote接口、方法需要抛出RemoteException异常

    public interface ServerService extends Remote {
    
        String demo(String content) throws RemoteException;
    
    }
    
    1.2 定义实现类

    要求:继承至UnicastRemoteObject类,该类实现了序列化接口

    public class ServerServiceImpl extends UnicastRemoteObject implements ServerService {
    
        public ServerServiceImpl() throws RemoteException {
        }
    
        @Override
        public String demo(String content) throws RemoteException {
            return content + "hello";
        }
        
    }
    
    1.3 启动

    执行下面的main方法:

    public class ServerTest {
    
        public static void main(String[] args) throws RemoteException, MalformedURLException, AlreadyBoundException {
            ServerService serverService = new ServerServiceImpl();
            //创建注册表
            LocateRegistry.createRegistry(8000);
            //以一个别名绑定该对象
            Naming.bind("rmi://localhost:8000/serverService", serverService);
    
            System.out.println("启动成功");
        }
    
    }
    

    2. 编写客户端

    新建一个客户端maven的module

    2.1 将对外接口拷贝一份
    2.2 获取远程对象,调用方法
    public class ClientTest {
    
        @Test
        public void get() throws RemoteException, MalformedURLException, NotBoundException {
            //获取远程对象
            ServerService service = (ServerService) Naming.lookup("rmi://localhost:8000/serverService");
    
            System.out.println("调用远程方法结果:" + service.demo("rmi"));
        }
    
    }
    

    结果:

    调用远程方法结果:rmihello

    四、RMI结合zookeeper实现RPC框架

    接下来使用RMI作为传输协议,zookeeper作为注册中心,实现RPC框架

    1. bean模块

    创建一个maven模块,作为公共的JavaBean

    定义一个实体类,实现序列化接口:

    public class User implements Serializable {
        private String username;
        private String password;
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public User() {
        }
    
        public User(String username, String password) {
            this.username = username;
            this.password = password;
        }
    }
    

    2. service模块

    创建Maven模块,作为rmi客户端和服务端两者共同使用的对外接口

    导入bean模块依赖:

            <dependency>
                <groupId>com.aruba</groupId>
                <artifactId>bean</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
    

    定义对外接口,继承至Remote接口:

    public interface UserService extends Remote {
    
        public List<User> getUserList() throws RemoteException;
    
    }
    

    3. provider模块

    创建Maven模块,作为服务端

    导入service模块依赖:

            <dependency>
                <artifactId>service</artifactId>
                <groupId>com.aruba</groupId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
    

    实现对外接口:

    public class UserServiceImpl extends UnicastRemoteObject implements UserService {
    
        public UserServiceImpl() throws RemoteException {
        }
    
        @Override
        public List<User> getUserList() throws RemoteException {
            List<User> list = Arrays.asList(new User("张三", "123"),
                    new User("李四", "456"));
    
            return list;
        }
    
    }
    

    启动方法:

    public class Run {
    
        public static void main(String[] args) throws IOException, AlreadyBoundException, InterruptedException, KeeperException {
            UserService serverService = new UserServiceImpl();
            //创建注册表
            try {
                LocateRegistry.createRegistry(8000);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            String url = "rmi://localhost:8000/userService";
            //以一个别名绑定该对象
            try {
                Naming.unbind(url);
            } catch (NotBoundException e) {
                e.printStackTrace();
            }
            Naming.bind(url, serverService);
    
            // 获取zooKeeper对象
            ZooKeeper zooKeeper = new ZooKeeper("192.168.42.4:2181", 10000, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
                    System.out.println("连接成功");
                }
            });
    
    
            //ZooDefs.Ids.OPEN_ACL_UNSAFE 表示权限。
            //CreateMode.PERSISTENT 永久存储。
            zooKeeper.create("/demos/userService", url.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            System.out.println("服务发布成功");
        }
    
    }
    

    4. consumer模块

    创建一个Maven模块,作为客户端

    导入SpringBoot依赖、service模块依赖:

        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-dependencies</artifactId>
                    <version>2.7.0</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
    ...
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>com.aruba</groupId>
                <artifactId>service</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
    
    4.1 service层

    定义service接口:

    public interface UserService {
    
        public List<User> getUserList() throws IOException, InterruptedException, KeeperException, NotBoundException;
    
    }
    

    service接口实现类:

    @Service
    public class UserServiceImpl implements UserService {
    
        @Override
        public List<User> getUserList() throws IOException, InterruptedException, KeeperException, NotBoundException {
            ZooKeeper zooKeeper = new ZooKeeper("192.168.42.4:2181", 10000, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
    
                }
            });
            // 通过zookeeper获取rmi的url
            byte[] url = zooKeeper.getData("/demos/userService", false, null);
    
            // 获取rmi的远程对象
            com.aruba.rmi.service.UserService userService = (com.aruba.rmi.service.UserService) Naming.lookup(new String(url));
    
            return userService.getUserList();
        }
    
    }
    
    4.2 controller层

    处理单元:

    @RestController
    public class UserController {
    
        @Autowired
        private UserService userService;
    
        @RequestMapping("/getUserList")
        public List<User> getUserList() throws NotBoundException, IOException, InterruptedException, KeeperException {
            return userService.getUserList();
        }
    
    }
    
    4.3 启动springboot
    @SpringBootApplication
    public class ConsumerApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApplication.class, args);
        }
    
    }
    

    浏览器访问结果:

    项目地址:

    https://gitee.com/aruba/rpcdemo.git

    相关文章

      网友评论

        本文标题:分布式--安装zookeeper、结合RMI实现RPC框架

        本文链接:https://www.haomeiwen.com/subject/pwcxvrtx.html