Java

RPC入门理解

2020-03-06  本文已影响0人  愤怒的老照

背景

最近几天准备学习thrift,百度百科解释:

Thrift是一种接口描述语言和二进制通讯协议,它被用来定义和创建跨语言的服务。它被当作一个远程过程调用(RPC)框架来使用,是由Facebook为“大规模跨语言服务开发”而开发的。

RPC又是啥?,忘光了,先从学习RPC开始

RPC概念

RPC,远程过程调用是一种技术思想而非一种规范或协议,常见的RPC框架和技术有:

其中,Thrift是 Facebook 的开源 RPC 框架,主要是一个跨语言的服务开发框架。
用户只要在其之上进行二次开发就行,应用对于底层的 RPC 通讯等都是透明的。不过这个对于用户来说需要学习特定领域语言这个特性,还是有一定成本的。

RPC实现

如果系统是单体应用,因为咋同一个进程,A想要调用B接口直接调用B()就可以了


image.png

如果采用分布式应用,就不能这样直接调用了


image.png

服务A和服务B并没有在同一个进程,必须采用网络调用

REST接口调用

模仿B/S架构,B应用暴露接口给A应用,A、B之间通过HTTPS来进行调用,但是A如果想使用HTTPS,在使用前就必须要编写HTTPS连接的代码,会造成很多重复代码,可以使用AOP切面编程,在业务逻辑开始和结束后,连接和释放连接。

RPC调用

如果采用HTTPS的方式,每次调用都要新建连接和释放连接。我们可以使用Socket。都可以,RPC并没有规定说你要用何种协议进行通讯。

image.png

RPC需要考虑的问题

要实现一个RPC不算难,难的是实现一个高性能高可靠的RPC框架。

比如,既然是分布式了,那么一个服务可能有多个实例,你在调用时,要如何获取这些实例的地址呢?

这时候就需要一个服务注册中心,比如在Dubbo里头,就可以使用Zookeeper作为注册中心,在调用时,从Zookeeper获取服务的实例列表,再从中选择一个进行调用。

那么选哪个调用好呢?这时候就需要负载均衡了,于是你又得考虑如何实现复杂均衡,比如Dubbo就提供了好几种负载均衡策略。

这还没完,总不能每次调用时都去注册中心查询实例列表吧,这样效率多低呀,于是又有了缓存,有了缓存,就要考虑缓存的更新问题,blablabla......

你以为就这样结束了,没呢,还有这些:

客户端总不能每次调用完都干等着服务端返回数据吧,于是就要支持异步调用;
服务端的接口修改了,老的接口还有人在用,怎么办?总不能让他们都改了吧?这就需要版本控制了;
服务端总不能每次接到请求都马上启动一个线程去处理吧?于是就需要线程池;
服务端关闭时,还没处理完的请求怎么办?是直接结束呢,还是等全部请求处理完再关闭呢?
......
如此种种,都是一个优秀的RPC框架需要考虑的问题。

可以直接使用现有的RPC框架,以Thrift为例。

Thrift 概述

Thrift最初由Facebook开发的,后来提交给了Apache基金会将Thrift作为一个开源项目。当时facebook开发使用它是为了解决系统中各系统间大数据量的传输通信以及系统之间语言环境不同需要跨平台的特性,所以Thrift是支持跨语言,比如C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml都支持。Thrift是一个典型的CS结构,客户端和服务端可以使用不同的语言开发。既然客户端和服务端能使用不同的语言开发,那么一定就要有一种中间语言来关联客户端和服务端的语言,没错,这种语言就是IDL(Interface Description Language)。

thrift-0.9.3.exe https://www.cnblogs.com/newboys/p/9366762.html

新建一个Thrift文件夹,将下载的thrift-0.9.1.exe重新命名为thrift.exe后放到Thrift文件夹下

配置环境变量,通过cmd thrift -version检查是否配置成功

Thrift DEMO

1、编写Apple.thrift(thrift idl的用法可转https://blog.csdn.net/u011642663/article/details/56015576

namespace java service.demo
service Apple{
    string appleString(1:string para);
    i32 appleAdd(1:i32 para);
    i32 appleMult(1:i32 para1,2:i32 para2);
}

2、使用thrift命令将idl转为java

thrift -r -gen java Apple.thrift

3、将生成的Apple.java复制到项目中,如果有@Override异常,去掉即可。

4、编写实现类

public class AppleServiceImpl implements Apple.Iface {
    public String appleString(String para) throws TException {
        return "apple print hello " + para;
    }

    public int appleAdd(int para) throws TException {
        return para+10;
    }

    public int appleMult(int para1, int para2) throws TException {
        return para1 - para2;
    }
}

5、编写Server

public class AppleServiceServer {

    public static void main(String[] args) throws TTransportException {
        System.out.println("apple 服务端开启。。");
        TProcessor tprocessor = new Apple.Processor<Apple.Iface>(new AppleServiceImpl());
        TServerSocket serverTransport = new TServerSocket(9000);
        TServer.Args tArgs = new TServer.Args(serverTransport);
        tArgs.processor(tprocessor);
        tArgs.protocolFactory(new TBinaryProtocol.Factory());

        TServer server = new TSimpleServer(tArgs);
        server.serve();
    }
}

6、编写Client端

public class AppleServiceClient {

    public static void main(String[] args) {
        System.out.println("客户端开始。。");
        TTransport transport = null;
        try{
            transport = new TSocket("localhost",9000,3000);
            TProtocol protocol = new TBinaryProtocol(transport);
            Apple.Client client = new Apple.Client(protocol);
            transport.open();

            String result = client.appleString("abc");
            System.out.println("服务端返回  。  " + result);

            int a = client.appleAdd(8);
            int b = client.appleMult(29, 3);
            System.out.println("a= " + a + "  b="+b);

        }catch(TTransportException e){
            e.printStackTrace();
        }catch(TException e){
            e.printStackTrace();
        }finally{
            if(null!=transport){
                transport.close();
            }
        }
    }

}

7、运行Server和Client


image.png
上一篇 下一篇

猜你喜欢

热点阅读