RPC框架原理

转自:https://www.jianshu.com/p/f67e9f6605d7

 

RPC调用是面向服务架构场景下进行服务间调用的常用组件,一个完整的RPC调用的流程如图1所示:

 

图1 RPC调用流程

为了方便RPC调用者和服务者的开发,开发者们开发了很多RPC框架。比较有名的RPC框架有Google的gRPC、Facebook的Thrift 和 阿里的 Dubbo 等。这些框架在具体实现上虽然各不相同,但其工作原理基本上是一致的。

一个设计良好的RPC框架的愿景是简化服务提供者和调用者的开发,将图1中 2~8 步骤的所有操作全部隐藏,让开发者可以像开发和调用本地方法一样开发和调用远程方法。为了隐藏这些实现细节,RPC框架需要关注如下几点:

  1. 方法调用:方法调用的过程如何转换为可以传输的消息内容;
  2. 服务发现:如何发布服务并告知调用者服务地址;
  3. 数据传输:服务调用者和提供者之间如何进行数据传输。

下面我们以Java语言为例,就以上几点分别做出分析。

1. 方法调用

1.1 “协议”设定

要完成一个完整的方法调用,需要在调用者和被调用者之间设计一套“协议”对被调接口、被调方法、参数类型、参数值、返回类型、返回值等进行定义,如下是一段比较合理的通信“协议”:

public class Request implements Serializable {
    private long sid;
    private String serviceName;
    private String methodName;
    private Class<?>[] paramTypes;
    private Object[] params;
}

public class Response implements Serializable {
    private long sid;
    private Class<?> resultType;
    private Object result;
}

Request里面,需要指定具体的服务、方法名,以及调用方法时需要传入的参数类型和参数值;Response里面直接指定返回值及其类型(因为返回值最多只有一个)。特别地,在Request 和 Response里面分别有一个 sid 字段,是为了在异步处理时能正确地对应请求和返回的关系。

1.2 请求、返回与“协议”对象的转化

为了简化服务方和调用方的实现,RPC框架里面需要完成方法请求与request对象之间的转换 和 处理结果与reponse对象之间的转换。对于Java,可以采用JDK的动态代理来实现这个转换;如果采用Spring框架,还可以通过Spring的动态代理类 -- FactoryBean进行实现。下面一段代码是通过JDK的动态代理实现本地调用转化为消息的一个demo:

// 动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class RpcProxyInvoker implements InvocationHandler {
    private Class<?> clazz;

    public RpcProxyInvoker(Class<?> clazz) {
        this.clazz = clazz;
    }

    public static Object getProxy(Class<?> clazz) {
        RpcProxyInvoker invoker = new RpcProxyInvoker(clazz);
        return Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] { clazz }, invoker);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Class<?>[] paramTypes = new Class[] {};
        for (int idx = 0; idx < args.length; ++idx) {
            paramTypes[idx] = args[idx].getClass();
        }

        Request req = new Request();
        req.setServiceName(clazz.getClass().getName());
        req.setMethodName(method.getName());
        req.setParameterTypes(paramTypes);
        req.setParameters(args);

        /// ... 后续操作:序列化、网络传输等
        return null;
    }
}

// 暴露给调用方的接口
public interface UserService {
    UserDTO get(int userId);
}

// 调用方调用简单示例
public class Main {
    public static void main(String[] args) {
        UserService userService = (UserService) RpcProxyInvoker.getProxy(UserService.class);
        userService.get(1);
    }
}

为了方便传输,需要对生成的Request对象进行序列化。最简单的序列化方法是采用Java的ObjectInput/OutputStream实现,当然也可以通过JSON等格式进行对象的序列化。
序列化结束后,交给网络模块进行网络传输并等待返回结果进行后续处理。

2. 服务发现

当RPC框架应用于大型分布式系统时,不可能将服务的地址人为地告知到每个调用方,应该自动化地完成这个“告知”工作。这个工作的流程如图2所示:

 

图2 服务发现

 

注册中心可以采用redis或者zookeeper等方式进行实现。
从服务提供者的角度看:当提供者服务启动时,需要自动向注册中心注册服务;当提供者服务停止时,需要向注册中心注销服务;提供者需要定时向注册中心发送心跳,一段时间未收到来自提供者的心跳后,认为提供者已经停止服务,从注册中心上摘取掉对应的服务。从调用者的角度看:调用者启动时订阅注册中心的消息并从注册中心获取提供者的地址;当有提供者上线或者下线时,注册中心会告知到调用者;调用者下线时,取消订阅。

3. 数据传输

服务提供者和调用者之间进行数据传输,可以借助基于端口的协议和基于HTTP的协议进行,如使用TCP协议通信 或 使用HTTP协议通信。通信方式上,可以使用传统的BIO(Blocked I/O) 或 NIO(New I/O)方式进行,在此不再一一赘述。

虽然RPC框架的原理比较简单,但要实现一个功能齐全、适应性强、对代码无侵入的RPC框架并非易事,需要在网络传输、序列化、Stub和Skeleton功能等方面下功夫。当然,在了解原理的情况下,使用一个RPC框架,对业务代码的编写和优化也有一定的促进作用。



作者:wwwwwwking
链接:https://www.jianshu.com/p/f67e9f6605d7
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

RPC(Remote Procedure Call)即远程过程调用,是一种通过网络使远程计算机程序能够调用另一个计算机上的子程序或服务的技术。在实现一个网盘服务时,RPC框架原理和实现是十分重要的。 首先,RPC框架允许客户端程序通过网络调用服务器端程序的子程序或服务。客户端发起请求时,通过序列化参数,并通过网络将请求信息发送给服务器端。服务器端接收到请求后,通过反序列化参数,调用相应的子程序或服务,并将结果序列化后返回给客户端。客户端再通过反序列化结果,得到最终的响应。 RPC框架的实现需要解决几个核心问题。首先,需要定义好请求和响应的消息格式,包括请求的方法名、参数等信息,以及响应的状态码和结果等信息。其次,需要实现序列化和反序列化的功能,将参数和结果转换为二进制流进行网络传输。通常使用JSON、XML或Protocol Buffers等数据交换格式来实现序列化和反序列化。另外,还需实现通信协议,如使用TCP/IP协议进行网络传输。最后,需要实现服务注册与发现、负载均衡和容错机制,以确保系统的可靠性和可扩展性。 在网盘服务的具体实现中,RPC框架可以用于客户端和服务器端之间的远程文件操作。例如,客户端发起上传文件的请求时,通过RPC框架将请求信息发送给服务器端,服务器端接收到请求后,调用相应的子程序将文件写入磁盘,并将结果返回给客户端。同样地,客户端可以通过RPC框架发送下载文件的请求,并获取服务器端返回的文件内容。 总而言之,深入理解RPC框架原理与实现对于设计和实现一个高效可靠的网盘服务是十分重要的。通过RPC框架,可以实现客户端和服务器端之间的远程过程调用,从而使网盘服务更加方便和易用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值