您的位置:

什么是RPC?

RPC(Remote Procedure Call)是一种通过网络从远程计算机程序中请求服务,而不需要了解底层网络技术的方式。RPC使得调用远程服务就像调用本地服务一样简单,将网络通信、数据传输等相关细节都封装在底层实现之中,使得上层应用程序可以像调用本地方法一样透明地调用远程方法。

一、RPC的概念与作用

RPC(Remote Procedure Call)意为远程过程调用,是一种常用的跨机器、跨进程的通信方式,通俗来讲,RPC就是一种接口,程序A通过调用RPC接口去请求程序B提供的服务。RPC的作用主要体现在分布式系统上,旨在让分布式系统的各个节点之间实现无缝通信,方便编程人员编写出更高效、更优雅的分布式系统。

RPC采用的是客户端与服务端之间的通信模式,客户端通过调用服务端的接口特定函数,请求服务端提供配置的服务。RPC使得调用远程服务就像调用本地服务一样简单,通过把网络通信、数据传输等相关细节都封装到底层实现之中,RPC使得上层应用程序可以像调用本地方法一样透明地调用远程方法,使得分布式计算系统更加容易使用,让开发人员能够将精力更集中在编写应用程序本身的业务逻辑上,可以更快地开发出线上服务。

RPC的工作流程大致分为下面这些步骤:

1.服务端启动,并监听一个网络地址;  
2.客户端发起连接请求;  
3.服务端接收到请求之后,将客户端所需要执行的请求内容(请求体)提取出来,并交由解析器进行解析,生成具体的执行指令;  
4.服务端开始执行指令,并将相应结果返回给客户端。  

二、RPC的实现方式

RPC的实现方式绝大部分都是基于网络的一些通信协议实现的,RPC协议目前已经被多种语言所支持,例如在Java中我们可以使用Dubbo、Thrift、gRPC 等框架进行RPC的实现。

下面来简单介绍下这几个框架:

Dubbo

Dubbo是阿里巴巴开发的一个高性能、轻量级的开源Java RPC框架,可以用于构建高性能和可扩展的分布式服务应用程序。

Dubbo采用了RPC通信模式,可以支持多种协议(默认基于Netty+Http),提供了零配置、智能负载均衡、自动容错等机制,支持以Spring为核心容器。

Dubbo的特性如下:

1. 快速编排:通过Dubbo提供的spring boot starter或官方提供的maven插件,便可几行配置完成dubbo的接入,可快速进行服务接入调试;
2. 注解丰富:Dubbo提供了大量的注解来管理dubbo服务,例如dubbo的服务提供者、服务消费者、reference注解、service注解、path注解等;
3. 服务治理:Dubbo提供了四种注册中心(ZooKeeper、Redis、Consul、Multicast)供我们选择,并提供了服务降级、服务熔断、流量分流等功能实现;
4. 高性能:通过协议的压缩和Dubbo FastJson的序列化,Dubbo可以快速的序列化和反序列化对象;
5. 特性丰富:Dubbo完全实现Dubbo特性,保证API的功能稳定性,同时接口粒度可以细化到每个方法,支持多种API级别的自定义配置。

Thrift

Thrift是一款高效的、支持自动代码生成的、可跨语言的RPC框架,由Facebook公司开发,用于处理大量跨语言服务调用的情况,目前已经成为了Apache的顶级项目。

Thrift主要支持数十种编程语言,因此称其为多语言 RPC 框架也不为过,通过代码生成器可以在多个应用程序之间自动序列化结构化数据,利用协议编解码技术将结构化的数据序列化后,进行网络传输,使得应用程序间的分布式调用就像本地方法一样简单。

Thrift的主要优点如下:

1. 可扩展性好:支持多种编程语言(如C++, Java, Python, Ruby, PHP等),对于开发人员来说非常方便和友好;
2. 可读性高:内置接口描述语言IDL,注重接口定义的清晰性和可读性,且IDL只与语言相关,不与协议相关,开发人员易于编写和理解;
3. 序列化协议多样化:支持几种常见的数据序列化协议(如TBinaryProtocol、TCompactProtocol、TJSONProtocol等),对于不同的使用场景都有选择;
4. 平台对接:Thrift支持多种平台的对接(如Java与C++、Python与Java等),支持多系统间的通信,便于实现分布式系统间的集成和调用;

gRPC

gRPC 是 Google 开发的下一代开源RPC框架,支持多种编程语言。gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、多项 RPC 支持等特性。通过 ProtoBuf 序列化协议来精简了消息大小。

它的优点如下:

1. 跨平台:gRPC支持多种语言(如Java、Python、C++等),可以互相进行调用,更加方便;
2. 传输格式:gRPC 默认使用 Protocol Buffers 作为数据传输格式,支持多种序列化方式,比如 Protobuf 和 JSON;
3. 压缩:gRPC 内置基于 HTTP/2 标准的压缩机制,能够大幅度减小通讯数据量,这对于流量敏感的应用、大流量应用等来说非常有意义;
4. 双向流:gRPC 实现了高级的流的支持,支持双向流、指定大小的流和单项流等多种流;
5. 动态集成:支持向已经搭建好的系统中无缝集成 grpc 服务,通过函数绑定,相互调用,无需其他复杂的配置;
6. 大型系统:gRPC 适用于大型系统,高并发,支撑负载均衡和限流等操作,可以通过多种语言去控制与调用。

三、RPC的应用场景

RPC的应用场景非常广泛,主要是针对分布式系统这个大家族的集群部署等场景。下面是一些比较常见的应用场景:

微服务

在微服务情况下,按照微服务架构的设计,各种属性的微服务可通过RPC技术实现相互之间的各种调用和访问。也就是各种微服务之间双向的客户端‐服务端调用,既可以实现同步调用,也可以做异步非阻塞调用,RPC可以通过微服务的Rest API实现,也可以直接通过直接函数调用实现例如:通过Grpc的封装JAVA客户端来调用Python的grpc服务。

分布式文件系统

分布式文件系统中集中设置文件访问机制比较常见,一般采用了基于RPC通信的客户端服务器模式。

分布式计算

分布式计算中,各个节点都需要协同工作,RPC 只是一种远程调用技术,但是整合 RPC 可以很好的帮助分布式计算协调完成任务。

在线协作编辑器

在线协作编辑器一般需要多个用户同时编辑同一个文档,用户对文档的操作会实时同步到其他用户的屏幕。RPC 十分适合这种场景,可将实时修改的内容通过服务端同步到其他用户屏幕中。

游戏行业

在游戏开发中,RPC 也是一个比较重要的技术之一,因为游戏中往往需要多个服务器提供计算和存储服务,采用 RPC 技术可使多个服务器之间互相通信、互相交互。

四、RPC的代码实例

下面给出一个简单的代码示例,演示了使用gRPC实现基本的远程调用。

步骤一:在服务端定义一个数据结构和一个RPC函数

syntax = "proto3";

package hello;

message HelloRequest {
    string name = 1;
}

message HelloResponse {
    string message = 1;
}

service HelloService {
    rpc hello(HelloRequest) returns (HelloResponse) {}
}

步骤二:使用gRPC框架生成的代码实现服务端函数

public class HelloServer extends HelloServiceGrpc.HelloServiceImplBase {
    @Override
    public void hello(HelloRequest request, StreamObserver<HelloResponse> responseObserver) {
        String message = "Hello " + request.getName() + "!";
        HelloResponse response = HelloResponse.newBuilder().setMessage(message).build();
        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }
}

步骤三:启动gRPC服务器,监听指定端口

Server server = ServerBuilder.forPort(8080)
    .addService(new HelloServer()).build().start();

System.out.println("Server started, listening on " + server.getPort());

server.awaitTermination();

步骤四:在客户端创建一个gRPC信道,发起请求

ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 8080).usePlaintext().build();
HelloServiceGrpc.HelloServiceBlockingStub stub = HelloServiceGrpc.newBlockingStub(channel);

HelloRequest request = HelloRequest.newBuilder().setName("World").build();
HelloResponse response = stub.hello(request);

System.out.println(response.getMessage());

总结

RPC技术凭着其高效性和透明性多方得到了广泛的应用。随着微服务的兴起和分布式技术的推广,RPC技术也将逐步成为构建分布式架构的一项重要基础技术。