如果自己实现RPC框架面对什么问题

RPC是一种通过网络进行远程服务调用的技术,其目标是让调用感觉像本地调用一样。文章详细阐述了RPC的调用流程,涉及代理问题、序列化和反射机制。同时,提到了Dubbo和SpringCloud这两个服务治理框架在网络通讯上的差异,包括通信协议、服务注册中心和服务调用方式等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是RPC?

RPC(Remote Procedure Call ——远程过程调用),它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络的技术。

一次RPC同步调用流程:

1)服务消费方(client)以本地调用方式调用客户端存根;

2)什么叫客户端存根?就是远程方法在本地的模拟对象,一样的也有方法名,也有方法参数,client stub接收到调用后负责将方法名、方法的参数等包装,并将包装后的信息通过网络发送到服务端;

3)服务端收到消息后,交给代理存根进行解码为实际的方法名和参数;

4) server stub根据解码结果调用服务器上本地的实际服务;

5)本地服务执行并将结果返回给server stub;

6)server stub将返回结果打包成消息并发送至消费方;

7)client stub接收到消息,并进行解码;

8)服务消费方得到最终结果。

RPC框架的目标就是要中间步骤都封装起来,让我们进行远程方法调用的时候感觉到就像在本地调用一样。

实现RPC框架需要解决的哪些问题

代理问题

代理本质上是要解决什么问题呢?要解决的是被调用的服务,本质上是远程的服务,但是调用者不知道也不关心,调用者只要结果,具体的事情由代理的那个对象来负责这件事。既然是远程代理,当然是要用代理模式了。

代理(Proxy)模式,通过代理对象访问目标对象。这样做的好处:在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。那我们这里额外的功能操作是干什么,通过网络访问远程服务。

jdk的代理有两种实现方式:静态代理和动态代理。

public class Client2 {
    //远程调用类
    public static IUserService getStub() throws Exception{
        //创建代理类 
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Socket socket = new Socket("127.0.0.1", 8888);
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                DataOutputStream dos = new DataOutputStream(out);
                dos.writeInt(13);
                socket.getOutputStream().write(out.toByteArray());
                socket.getOutputStream().flush();

                DataInputStream dis = new DataInputStream(socket.getInputStream());
                int ReceId = dis.readInt();
                String name = dis.readUTF();
                User user = new User(ReceId, name);
                dos.close();
                socket.close();
                return user;
            }
        };
        //执行动态代理(传入类加载器、接口、代理对象; 返回对象)
        Object o = Proxy.newProxyInstance(IUserService.class.getClassLoader(),
                new Class[]{IUserService.class},handler);
        return (IUserService)o;
    }
}

序列化问题

序列化问题在计算机里具体是什么?我们的方法调用,有方法名,方法参数,这些可能是字符串,可能是我们自己定义的java的类,但是在网络上传输或者保存在硬盘的时候,网络或者硬盘并不认得什么字符串或者javabean,它只认得二进制的01串,怎么办?要进行序列化,网络传输后要进行实际调用,就要把二进制的01串变回我们实际的java的类,这个叫反序列化。java里已经为我们提供了相关的机制Serializable。

举例,登记的服务实例化。

登记的服务有可能在我们的系统中就是一个名字,怎么变成实际执行的对象实例,当然是使用反射机制。

反射机制是什么?

反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取信息以及动态调用对象的方法的功能称为反射机制。

反射机制主要提供了以下功能:

•在运行时判断任意一个对象所属的类;

•在运行时判断任意一个类所具有的成员变量和方法;

•在运行时构造任意一个类的对象;

•在运行时调用任意一个对象的方法;

•生成动态代理。

public class Client3 {
    //远程调用类
    public static Object getStub(final Class clazz) throws Exception{
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Socket socket = new Socket("127.0.0.1", 8888);
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                //TODO 送入的class 灵活了
                String className = clazz.getName();
                String methodName = method.getName();
                Class[] parametersTypes = method.getParameterTypes();
                //TODO 传递class到服务器
                oos.writeUTF(className);

                oos.writeUTF(methodName);
                oos.writeObject(parametersTypes);
                oos.writeObject(args);
                oos.flush();
                //TODO 返回对象
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                Object o = ois.readObject();
                oos.close();
                socket.close();
                return o ;
            }
        };
        Object o = Proxy.newProxyInstance(clazz.getClassLoader(),
                new Class[]{clazz},handler);
        return o;
    }
}
/**
 * 服务端:服务更灵活-提供多个类、多个方法的远程接口调用
 */
public class Server3 {
    private static boolean running = true;
    public static void main(String[] args) throws  Exception{
        ServerSocket serverSocket = new ServerSocket(8888);
        while (running){
            Socket socket = serverSocket.accept();
            process(socket);
            socket.close();
        }
        serverSocket.close();
    }
    private static void  process(Socket socket) throws Exception{
        InputStream in = socket.getInputStream();
        OutputStream out = socket.getOutputStream();
        ObjectInputStream ois = new ObjectInputStream(in);
        //TODO 拿到客户端传递过来的class
        String clazzName =ois.readUTF();

        String methodName =ois.readUTF();
        Class[] parameterTypes = (Class[])ois.readObject();
        Object[] args =(Object[])ois.readObject();
        //反射拿到class
        Class clazz =Class.forName(clazzName);
        if(clazz.isInterface()){
            if(clazzName.equals("com.ivy.netty.pre.IUserService")){
                clazz = UserServiceImpl.class;
            }
           //这里可以使用反射机制拿到所有接口对应的实现类
        }

        Method method = clazz.getMethod(methodName,parameterTypes);

        Object object = method.invoke(clazz.newInstance(),args);
        //TODO 返回值:使用对象进行返回
        ObjectOutputStream oos = new ObjectOutputStream(out);
        oos.writeObject(object);
        oos.flush();
    }
}

Dubbo是一个典型的RPC运用

image.png

  1. 服务容器负责启动,加载,运行服务提供者。

  2. 服务提供者在启动时,向注册中心注册自己提供的服务。

  3. 服务消费者在启动时,向注册中心订阅自己所需的服务。

  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。

  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。

  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

在网络通讯上,Dubbo和SpringCloud的差别

Dubbo和Spring Cloud都是目前非常流行的服务治理框架,它们都提供了分布式微服务的解决方案。在网络通讯上,Dubbo和Spring Cloud有以下差别:

  1. 通信协议: Dubbo使用自定义的RPC通信协议,支持多种序列化方式,如Hessian、Java序列化、JSON等。而Spring Cloud使用的是HTTP或其他的基于HTTP的RESTful风格的通信协议。
  2. 服务提供者和消费者的关系: Dubbo采用的是服务提供者和消费者的直连模式,消费者需要知道服务提供者的IP地址和端口号才能进行调用。而Spring Cloud是通过服务注册和发现机制构建的分布式系统,服务消费者只需要使用服务名即可调用相应的服务,无需关心服务提供者的IP地址和端口号。
  3. 服务注册中心: Dubbo采用Zookeeper作为默认的服务注册中心,而Spring Cloud可以使用Eureka、Nacos、Consul、Zookeeper等多种服务注册中心。
  4. 服务调用方式: Dubbo只支持同步调用方式,消费者发送请求到提供者并等待响应结果,而Spring Cloud支持同步和异步两种调用方式。
  5. 在性能方面,Dubbo的性能较Spring Cloud更加优秀。

需要注意的是,Dubbo和Spring Cloud并不是竞争关系,而是在不同的应用场景和业务需求下选择不同的技术架构。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值