高性能Java RPC框架Dubbo与zookeeper的使用

一. 什么是RPC

1. RPC 协议(Remote Procedure Call Protocol)

远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC 协议假定某些传输协议的存在,如 TCP 或 UDP,为通信程序之间携带信息数据。在 OSI 网络通信模型中,RPC 跨越了传输层和应用层。RPC 使得开发包括网络分布式程序在内的应用程序更加容易。
RPC 采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。

2. RPC 框架

在单机时代一台电脑运行多个进程,进程之间无法通讯,显然这会浪费很多资源,因此后来出现 IPC(Inter-process communication: 单机中运行的进程之间的相互通信 ),这样就能允许进程之间进行通讯,比如在一台计算机中的 A 进程写了一个吃饭的方法,那在以前如果在 B 进程中也要有一个吃饭的方法,必须要在 B 进程中进行创建,但有了 RPC 后 B 只需要调用 A 进程的程序即可完成,再到后来网络时代的出现, 大家电脑都连起来,这时可不可以调用其他电脑上的进程呢,当然可以,这样 RPC 框架就出现了。
严格意义上来讲:Unix的生态系统中 RPC 可以在同一台电脑上不同进程进行,也可以在不同电脑上进行;而在windows 里面同一台电脑上不同进程间的通讯还可以采用 LPC(本地访问)。综上:RPC 或 LPC是上层建筑,IPC 是底层基础。
RPC 框架有很多:比如 Thrift、dubbo、grpc 等。

3. RPC 与 HTTP 、TCP 、UDP 、Socket 的区别

TCP/UDP: 都是传输协议,主要区别是 tcp 协议连接需要 3 次握手,断开需要四次挥手,是通过来传输的,就是确定连接后,一直发送信息,传完后断开。udp 不需要进行连接,直接把信息封装成多个报文,直接发送。所以 udp 的速度更快写,但是不保证数据的完整性
HTTP: 超文本传输协议是一种应用层协议,建立在 TCP 协议之上
Socket: 是在应用程序层面上对 TCP/IP 协议的封装和应用。其实是一个调用接口,方便程序员使用 TCP/IP 协议栈而已。程序员通过 socket 来使用 tcp/ip 协议。但是 socket 并不是一定要使用 tcp/ip 协议,Socket 编程接口在设计的时候,就希望也能适应其他的网络协议。
小结: 我们把网络传输类比于一条公路,那 TCP/UDP 就是货车,HTTP 就是货物,而 socket就是发动机。
RPC 是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。所以 RPC 的实现可以通过不同的协议去实现比如可以使 http、RMI 等。

4. RPC 的运行流程

首先, 要解决通讯的问题,主要是通过在客户端和服务器之间建立 TCP 连接,远程过程调用的所有交换的数据都在这个连接里传输。连接可以是按需连接,调用结束后就断掉,也可以是长连接,多个远程过程调用共享同一个连接。
第二, 要解决寻址的问题,也就是说,A 服务器上的应用怎么告诉底层的 RPC 框架,如何连接到 B 服务器(如主机或 IP 地址)以及特定的端口,方法的名称名称是什么,这样才能完成调用。比如基于Web服务协议栈的RPC,就要提供一个endpoint URI,或者是从UDDI(一种目录服务,通过该目录服务进行服务注册与搜索)服务上查找。如果是 RMI 调用的话,还需要一个 RMI Registry 来注册服务的地址。
第三, 当 A 服务器上的应用发起远程过程调用时,方法的参数需要通过底层的网络协议如 TCP 传递到 B 服务器,由于网络协议是基于二进制的,内存中的参数的值要序列化成二进制的形式,也就是序列化(Serialize)或编组(marshal),通过寻址和传输将序列化的二进制发送给 B 服务器。
第四, B 服务器收到请求后,需要对参数进行反序列化(序列化的逆操作),恢复为内存中的表达方式,然后找到对应的方法(寻址的一部分)进行本地调用,然后得到返回值。
第五, 返回值还要发送回服务器 A 上的应用,也要经过序列化的方式发送,服务器 A 接到后,再反序列化,恢复为内存中的表达方式,交给 A 服务器上的应用
高性能Java RPC框架Dubbo与zookeeper的使用_第1张图片
JAVAEE 里面的 stub 是为屏蔽客户调用远程主机上的对象,必须提供某种方式来模拟本地对象,这种本地对象称为存根(stub), 存根负责接收本地方法调用,并将它们委派给各自的具体实现对象
Skeleton:服务器的骨架

5. RPC 基于RMI的简单实现

5-1 首先建一个多模块的maven项目, 结构如下:

高性能Java RPC框架Dubbo与zookeeper的使用_第2张图片

5-2 rpc_rmi_api模块实现, 就是提供调用的接口, 结构图如下:

高性能Java RPC框架Dubbo与zookeeper的使用_第3张图片

User类:(必须实现序列化接口)
public class User implements Serializable {

    private static final long serialVersionUID = 6290816946970912418L;
    private Integer id;
    private String userName;
    private String userPwd;

    public User(Integer id, String userName, String userPwd) {
        this.id = id;
        this.userName = userName;
        this.userPwd = userPwd;
    }

    public User(){

    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                ", userPwd='" + userPwd + '\'' +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public static long getSerialVersionUID() {
        return serialVersionUID;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserPwd() {
        return userPwd;
    }

    public void setUserPwd(String userPwd) {
        this.userPwd = userPwd;
    }
}
UserService接口:(相关规定看注释)
public interface UserService extends Remote { //规定继承Remote父类

    public User queryUserById(Integer userId) throws RemoteException; //规定抛出异常
}
5-3 rpc_rmi_provider的模块实现,结构图如下:(主要提供服务)

高性能Java RPC框架Dubbo与zookeeper的使用_第4张图片

UserServiceImp类实现: (要继承UnicastRemoteObject 类,规定的)
public class UserServiceImp extends UnicastRemoteObject implements UserService {

    private Map<Integer, User> users = new HashMap<Integer, User>();

    public UserServiceImp() throws RemoteException{

        users.put(1,new User(1,"admin","123456"));
        users.put(2,new User(2,"shsxt","123456"));

    }

    @Override
    public User queryUserById(Integer userId) throws RemoteException {
        return users.get(userId);
    }
}
Publisher类的实现:(发布服务端)
public class Publisher {
    
    public static void main(String[] args) throws RemoteException, AlreadyBoundException, MalformedURLException {
        //指定服务端口
        LocateRegistry.createRegistry(8989);
        //发布服务
        Naming.bind("rmi://192.168.1.158:8989/userService", new UserServiceImp());
        
        System.out.println("成功发布服务!!!");
    }
}
5-4 rpc_rmi_consumer结构图如下:(客户端的调用)

高性能Java RPC框架Dubbo与zookeeper的使用_第5张图片

App 类的实现:(调用服务端)
public class App {
    public static void main( String[] args ) throws RemoteException, NotBoundException, MalformedURLException {
        UserService userService = (UserService) Naming.lookup("rmi://192.168.1.158:8989/userService");
        System.out.println(userService.queryUserById(2));
    }
}

结果:
在这里插入图片描述

二. Dubbo框架

1. 框架基本概念

官网: http://dubbo.apache.org/en-us/
A high performance Java RPC framework ----一个高效的远程调用框架
高性能Java RPC框架Dubbo与zookeeper的使用_第6张图片
Dubbo 是由阿里巴巴开源的一个高性能、基于 Java 开源的远程调用框架。正如在许多RPC 系统中一样,dubbo 是基于定义服务的概念,指定可以通过参数和返回类型远程调用的方法。在服务器端,服务器实现这个接口,并运行一个 dubbo 服务器来处理客户端调用。在客户端,客户机有一个存根,它提供与服务器相同的方法。
dubbo的架构图:
高性能Java RPC框架Dubbo与zookeeper的使用_第7张图片
Dubbo 提供三个核心功能:基于接口的远程调用、容错和负载均衡,以及服务的自动注
册与发现。Dubbo 框架广泛的在阿里巴巴内部使用,以及京东、当当、去哪儿、考拉等都在
使用。

2. Dubbo快速入门

这里也是从实战出发,搭建一个简单的远程调用小实例, 首先也是要创建一个maven的多模块项目, 结果图如下:
高性能Java RPC框架Dubbo与zookeeper的使用_第8张图片
下面来一个模块一个模块的列出来:

2-1 dubbo_api 模块的结构图如下:(也是提供方法调用接口)

高性能Java RPC框架Dubbo与zookeeper的使用_第9张图片
大家不用像我建的那么深,我的错误; 里面的User与UserService与上面的rmi一样;

2-2 dubbo_provider的结构图如下:

高性能Java RPC框架Dubbo与zookeeper的使用_第10张图片

UserServiceImp类的实现:(与上面不一样的是不用继承那个鬼类啦!)
@Service
public class UserServiceImp implements UserService {

    private Map<Integer, User> users = new HashMap<>();

    public UserServiceImp(){
        users.put(1,new User(1,"admin","123456"));
    }

    @Override
    public User queryUserById(Integer userId) {
        return users.get(userId);
    }
}
Publisher类的实现,与上面完全不同:
public class Publisher {

    public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("provider.xml");
        context.start();
        System.out.println("服务发布成功!!!");
        System.in.read(); //按任意键退出
    }
}
配置文件provider.xml的实现
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://code.alibabatech.com/schema/dubbo
       http://code.alibabatech.com/schema/dubbo/dubbo.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.shsxt.provider"/>

    <!--
        dubbo 环境配置
    -->

    <!--应用名称-->
    <dubbo:application name="dubbo_provider"></dubbo:application>

    <!--注册中心配置:广播地址-->
    <dubbo:registry address="multicast://224.5.6.7:1234"></dubbo:registry>

    <!--指定公布的服务使用的协议与端口号-->
    <dubbo:protocol name="dubbo" port="20880"></dubbo:protocol>

    <!--配置公布的服务-->
    <dubbo:service interface="com.shsxt.api.service.UserService" ref="userServiceImp"></dubbo:service>

</beans>
2-3 dubbo_consumer 模块买的实现, 结构图如下:

高性能Java RPC框架Dubbo与zookeeper的使用_第11张图片

UserController类的实现
@Controller
public class UserController {
    @Resource
    private UserService userService;
    
    public User queryUserById(Integer userId){
        return userService.queryUserById(userId);
    }
}
App类的实现
public class App {
    public static void main( String[] args ) {

        ApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml");
        UserController userController = (UserController) context.getBean("userController");
        
        System.out.println(userController.queryUserById(1));
        
    }
}
配置文件consumer.xml的代码(注意与provider.xml比较一下区别)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://code.alibabatech.com/schema/dubbo
       http://code.alibabatech.com/schema/dubbo/dubbo.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.shsxt.consumer"/>

    <!--
       dubbo 环境配置
    -->

    <!--配置应用名称-->
    <dubbo:application name="dubbo_consumer"></dubbo:application>

    <!--指定注册中心-->
   <dubbo:registry address="multicast://224.5.6.7:1234"></dubbo:registry>
 
    <!--配置订阅的服务列表-->
    <dubbo:reference id="userService" interface="com.shsxt.api.service.UserService"></dubbo:reference>

</beans>
2-4 最后在主项目的pom.xml中加入下面依赖:(主项目中有单元测试,其他三个子模块的单元测试可以删除掉)
 <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!--引入dubbo依赖-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.5.6</version>
        </dependency>
 </dependencies>

三. 几种重要配置的介绍

1. dubbo:application

应⽤信息配置。对应的配置类:com.alibaba.dubbo.config.ApplicationConfig,下面是官网的大致配置介绍,详细介绍直接去官网查看: http://dubbo.apache.org/en-us/docs/user/references/xml/dubbo-service.html
高性能Java RPC框架Dubbo与zookeeper的使用_第12张图片

	标签					目的										介绍
dubbo:service	     服务出口	  		 用于导出服务,定义服务元数据,使用多个协议导出服务,向多个注册表注册服务
dubbo:reference	 	 服务参考	 		 用于创建远程代理,订阅多个注册表
dubbo:protocol	     协议配置	  		 在供应商方面配置服务协议,消费者方面如下。
dubbo:application	 应用程序配置	 		 适用于提供者和消费者。
dubbo:module	     模块配置    	  	 可选的。
dubbo:registry		 注册中心			 注册表信息:地址,协议等
dubbo:monitor		 监控中心			 监控信息:地址,地址等。可选。
dubbo:provider		 提供商的默认配置		 ServiceConfigs的默认配置。可选的。
dubbo:consumer	 	 消费者的默认配置	 	 ReferenceConfigs的默认配置。可选的。
dubbo:method		 方法级别配置			 ServiceConfig和ReferenceConfig的方法级别配置。
dubbo:argument	 	 参数配置			 用于指定方法参数配置。

2. dubbo:registry

注册中⼼配置。对应的配置类: com.alibaba.dubbo.config.RegistryConfig。同时如果有多个不 同的注册 中⼼, 可以声 明多个 dubbo:registry 标签 ,并在 dubbo:service 或dubbo:reference 的 registry 属性指定使⽤的注册⼼。

3. dubbo:protocol

服务提供者协议配置。对应的配置类:com.alibaba.dubbo.config.ProtocolConfig,同时, 如果需要⽀持多协议, 可以声明多个 dubbo:protocol 标签, 并在 dubbo:service 中通过protocol 属性指定使⽤的协议

4. dubbo:service

服务提供者暴露服务配置。对应的配置类:com.alibaba.dubbo.config.ServiceConfig

5. dubbo:reference

服务消费者引⽤服务配置。对应的配置类: com.alibaba.dubbo.config.ReferenceConfig

四. zookeeper安装与注册中心配置

高性能Java RPC框架Dubbo与zookeeper的使用_第13张图片
上面为zookeeper的主要工作结构图

流程说明:
  • 服务提供者启动时: 向/dubbo/com.foo.BarService/providers 目录下写入自己的 URL 地址
  • 服务消费者启动时: 订阅 /dubbo/com.foo.BarService/providers 目录下的提供者 URL 地址。并向 /dubbo/com.foo.BarService/consumers 目录下写入自己的URL 地址
  • 监控中心启动时: 订阅 /dubbo/com.foo.BarService 目录下的所有提供者和消费者 URL 地址。
支持以下功能:
  • 当提供者出现断电等异常停机时,注册中心能自动删除提供者信息
  • 当注册中心重启时,能自动恢复注册数据,以及订阅请求
  • 当会话过期时,能自动恢复注册数据,以及订阅请求
  • 当设置 时,记录失败注册和订阅请求,后台定时重试
  • 可 通 过 设 置zookeeper 登录信息
  • 可通过 设置 zookeeper 的根节点,不设置将使用无根树
  • 支持 * 号通配符 ,可订阅服务的所有分组和所有版本的提供者

1. zookeeper的下载及安装(linux环境)

为啥是linux呢? 简单+不卡啊!

1-1 下载
在你认为合适的位置建一个文件夹: mkdir + 文件夹名
进入该目录进行下载操作:  wget  http://mirrors.hust.edu.cn/apache/zookeeper/zookeeper-3.4.10/zookeeper-3.4.10.tar.gz
1-2 解压
tar  -zvxf  + 你要解压的压缩包

解压完成后的目录结构
高性能Java RPC框架Dubbo与zookeeper的使用_第14张图片

1-3 启动前的热身运动

如果你直接去bin目录启动zookeeper服务器的话会报错, 错误为:不能在conf中找到zoo.cfg这个配置文件, 因为一开始conf里面只有一个zoo_sample_cfg , 所以我们先在conf目录下赋值一份, 名为zoo.cfg

cp  zoo_sample_cfg  zoo.cfg

高性能Java RPC框架Dubbo与zookeeper的使用_第15张图片

用vim命令打开zoo.cfg文件,  vim zoo.cfg  内容如下:

高性能Java RPC框架Dubbo与zookeeper的使用_第16张图片
每个配置对应的解释详细也能看懂,就不介绍了,可以不用改就可以跑去bin目录下启动啦!

1-4 正式启动(bin目录下)
 ./zkServer.sh start  (注意是要加start的) 启动服务端
./zkCli.sh  为启动客户端

2. 对应的java配置

2-1 在 provider和consumer 中增加 zookeeper 客户端 jar 包依赖:
<!--zookeeper配置-->
<dependency>
	<groupId>org.apache.zookeeper</groupId>
	<artifactId>zookeeper</artifactId>
	<version>3.3.3</version>
</dependency>
<!--zkclient客户端-->
<dependency>
	<groupId>com.github.sgroschupf</groupId>
	<artifactId>zkclient</artifactId>
	<version>0.1</version>
</dependency>

上面使用了zkclient客户端连接,除了这个还可以使用curator客户端连接, 相应的依赖为:

<dependency>
	<groupId>com.netflix.curator</groupId>
	<artifactId>curator-framework</artifactId>
	<version>1.1.10</version>
</dependency>
2-2 Zookeeper 单机配置

就是改对应的provider与consumer模块的xml配置即可

<dubbo:registry address="zookeeper://10.20.153.10:2181" />
<dubbo:registry protocol="zookeeper" address="10.20.153.10:2181" />
2-3 Zookeeper 集群配置

不同的ip用逗号隔开

<dubbo:registry address="zookeeper://10.20.153.10:2181?backup=10.20.153.11:2181,10.20.153.12:2181" />
<dubbo:registry protocol="zookeeper" address="10.20.153.10:2181,10.20.153.11:2181,10.20.153.12:2181" />
2-4 同一 Zookeeper分成多组注册中心
<dubbo:registry id="chinaRegistry" protocol="zookeeper" address="10.20.153.10:2181" group="china" />
<dubbo:registry id="intlRegistry" protocol="zookeeper" address="10.20.153.10:2181" group="intl" />

我们上面的为单机版的就行,然后启动java里面的服务端与客户程序的代码就行了, 因为zookeeper管理dubbo为树形结构,使用可以查看注册中心的服务情况, 如下用ls 命令查看就行, 查看根节点为:

ls /dubbo  (记得前面加/) 想查看哪一级的进哪一级查看就行

在这里插入图片描述

你可能感兴趣的:(其他框架技术)