dubbo——RPC

一、RPC的定义

 RPC:是Remote Procedure Call的缩写,中文名远程过程调用。RPC协议是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一个地址空间(通常为一个开发网络的一台计算机)的子程序,而程序员就像调用本地程序一样,无需额外地为这个交互作用编程。如果涉及的软件采用面向对象编程,那么远程过程调用亦可称为远程方法调用,例:Java RMI。

RPC有以下优势:

简单。RPC的语义十分清晰简单,便于建立分布式系统

高效。能高效的实现远程过程调用。

通用。RPC导出的服务可以供多个使用者用于不同的目的

二、RPC调用过程

1 客户端调用客户端的stub(client stub)。这个调用是在本地,并将调用参数push到栈(stack)中。

2 客户端stub(client stub)将这些参数包装,并通过系统调用发送到服务器机器。打包的过程叫marshalling。(常见方式:XML、JSON、二进制编码)

3 客户端本地操作系统发送信息至服务器。(可通过自定义的TCP协议或HTTP协议传输)

4 服务器系统将信息传送至服务端stub(server stub)。

5 服务端stub(server stub)解析信息。这个过程叫unmarshalling。

6 服务端stub(server stub)调用程序,并把结果返回到服务端stub(server stub)中

7 服务器stub(server stub)将返回参数包装(marshalling),并通过系统调用发送到客户端机器。

8 客户端系统将返回信息传送到客户端stub(client stub)。

9 客户端存根从本地socket接口中读取结果信息。

10 客户端存根unmarshalling后,再将结果返回给客户端函数。

 关于stub存根的个人理解:第一次见stub存根,不知道存根具体是什么,个人理解,存根就是一个抽象的概念。

只需要记住存根实现的功能:marshalling+unmarshalling、查找服务端提供服务地址、并调用操作系统的系统通用接口,控制socket传输数据。

那么在具体RPC协议的具体实现中,实现这一块逻辑的模块,我就认为是stub存根。

 补充:

PRC协议在传输层与应用层之间。

IDL:interface definition language,接口定义语言。用来化解各个语言之间的特殊性。即RPC可跨语言调用

三、Java中实现RPC协议的框架

1、Java RMI

JavaRMI(Remote Method Invocation)是JDK提供的RPC协议实现,只支持Java语言,不能跨语言调用(没有使用IDL),因此简单、实用、效率高。

与上面RPC流程图不同是:Java RMI增加了一个命名服务(注册)。

命名服务的作用:把查找服务端服务地址的逻辑从本地存根stub中解耦出去,利用一个独立的注册空间实现。好处:

① 未提供服务早发现,例如:服务器奔溃

② 更利于分布式环境实现。网状结构(每台机器都需要管理服务地址,而且需要保证一致性)-->总线结构(由命名服务统一管理)

③ 统一的管理利于服务监控的实现。

RMI中分布式垃圾收集:

RMI创建了一个分布式环境,使客户端JVM上的进程可以访问服务端JVM进程中的对象。这意味着服务端JVM进程需要知道一个对象在什么时候不再被客户引用,并且可以被垃圾回收。

在使用RMI的JVM中,Java支持两种操作:标记脏数据和清理。当对象仍在使用时,客户端JVM会定期向服务端JVM发送一个标记脏数据的调用(类似于定期心跳检测)。当客户端JVM不再使用时,会发送一个清理的调用给服务端JVM,服务端JVM根据客户端发送信息,及本地对象使用情况,进行垃圾回收。RMI实现可分为三层:

简单代码实现:

public class Person implements Serializable {
    //必须支持序列化
    private static final long serialVersionUID = 1L;

    private int id;
    private String name;
    private int age;

    //省略getter/setter
}

public interface PersonService extends Remote {
    //接口必须实现Remote,方法必须throws RemoteException
    Person getPersonInfo(int n) throws RemoteException;
}    

public class PersonServiceImpl extends UnicastRemoteObject implements PersonService {
    //具体实现类,UnicastRemoteObject提供远程调用基础功能
    protected PersonServiceImpl() throws RemoteException {
    }

    @Override
    public Person getPersonInfo(int id) throws RemoteException {
        System.out.println("get Person :" + id);
        Person person = new Person();
        person.setId(id);
        return person;
    }
}

public class Server {
    //服务端启动
    public static void main(String[] args) {
        try {
            PersonService personService = new PersonServiceImpl();
            //提供服务的端口
            LocateRegistry.createRegistry(5555);
            //注册接口命名
            Context namingContext = new InitialContext();
            namingContext.rebind("rmi://localhost:5555/PersonService", personService);
            //Naming.rebind("rmi://localhost:6666/person-service",personService);
            System.out.println("Service started");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public class Client {
    //客户端启动
    public static void main(String[] args) {
        try {
            //远程对象调用的端口和注册类
            PersonService personService = (PersonService) Naming.lookup("rmi://localhost:5555/PersonService");
            Person person = personService.getPersonInfo(5);
            System.out.println(person);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2、基于RPC协议的SOA框架

① SOA:

 SOA:全称service-oriented architecture,面向服务的体系结构,它并不特指一种技术,而是一种分布式运算的软件设计方法。软件的部分组件(调用者),可以透过网络上的通用协议用另外一个应用软件组件运行、运作(与RPC契合)。让调用者获得服务。SOA将一项服务视为一个独立的功能单元,可以远程访问并独立运行与更新,例如在线查询信用卡账单。

企业系统的架构师认为SOA能够帮助业务迅速和高效地响应变化的市场条件。服务的导向架构在宏观(服务)上,而不是在微观上(对象),因此提高了重复使用性。

我简单理解就是面向服务编程。将服务视作一个对象。SOA使分布式系统设计更加清晰了,以服务为单位,将系统拆分。

②基于RPC协议的SOA框架——dubbo

 基于PRC协议实现的SOA框架有很多,Facebook的Thrift、ZeroC的Ice、谷歌的gRPC、阿里巴巴的Dubbo。国内使用最多的是dubbo,所以接下来会慢慢研究下dubbo实现。

dubbo是阿里巴巴在2011年开源的分布式服务架构,是SOA服务化治理方案的核心框架。

dubbo简单代码使用:

API实现:

public interface GreetingService {
    String sayHi(String name);
}

public class GreetingServiceImpl implements GreetingService {
    @Override
    public String sayHi(String name) {
        return "hi, " + name;
    }
}

public class Application {

    public static void main(String[] args) throws InterruptedException {
        ServiceConfig<GreetingService> service = new ServiceConfig<>();
        service.setApplication(new ApplicationConfig("first-dubbo-provider"));
        service.setRegistry(new RegistryConfig("zookeeper://mcip:2291?backup=mcip:2292,mcip:2293"));
        service.setInterface(GreetingService.class);
        service.setRef(new GreetingServiceImpl());
        service.export();

        System.out.println("dubbo service started");
        new CountDownLatch(1).await();
    }
}

public class ApplicationB {
    private static String zookeeperHost = System.getProperty("zookeeper.address","mcip");

    public static void main(String[] args) throws InterruptedException {
        ReferenceConfig<GreetingService> reference = new ReferenceConfig<>();
        reference.setApplication(new ApplicationConfig("first-dubbo-consumer"));
        reference.setRegistry(new RegistryConfig("zookeeper://mcip:2291?backup=mcip:2292,mcip:2293"));
        reference.setInterface(GreetingService.class);
        GreetingService service =reference.get();
        System.out.println(service.sayHi("dubbo"));
    }
}

基于springxml实现:

provider:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       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://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
       http://dubbo.apache.org/schema/dubbo   http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

       <context:property-placeholder/>

       <!-- provider's application name, used for tracing dependency relationship -->
       <dubbo:application name="dubbo-demo"/>
       <!-- use multicast registry center to export service -->
       <dubbo:registry address="${dubbo.zk.address}"/>
       <!-- use dubbo protocol to export service on port 20880 -->
       <dubbo:protocol name="dubbo" port="${dubbo.port}" />
       <!-- service implementation, as same as regular local bean -->
       <dubbo:service interface="org.study.service.UserService" ref="userService" protocol="dubbo"/>
</beans>

consumer:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       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://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
       http://dubbo.apache.org/schema/dubbo   http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

       <context:property-placeholder/>

       <!-- provider's application name, used for tracing dependency relationship -->
       <dubbo:application name="dubbo-demo1"/>
       <!-- use multicast registry center to export service -->
       <dubbo:registry address="zookeeper://mcip:2291?backup=mcip:2292,mcip:2293"/>
       <!-- use dubbo protocol to export service on port 20880 -->
       <dubbo:protocol name="dubbo" port="20881" />
       <!-- service implementation, as same as regular local bean -->
       <dubbo:reference interface="org.study.service.UserService" id="userService"/>
</beans>

参考  维基百科、《可伸缩服务架构-框架与中间件》、dubbo官网

原文地址:https://www.cnblogs.com/wqff-biubiu/p/12484076.html