基于Netty的RPC框架

概述

RPC(Remote Procedure Call),远程过程调用,是一个计算机通信协议,该协议允许运行一个进程调用另一个进程,而程序员无需额外为这个交互作用编程。

两个或者多个应用程序分布在不同的服务器上,他们之间的调用在客户端看来,就跟调用本地方法一样。

场景的RPC框架用阿里的dubbo、Google的gRPC,Apache的thrift、spring 的SpringCloud等。

调用流程:
在这里插入图片描述
clientsub是客户端本地调用的代理,ServerSub是服务端的代理。
流程解释:

  1. 服务消费端本地调用方式来调用远程服务。
  2. ClientSub接收到调用后,负责将方法,参数等,封装成能够进行网络传输的消息体。
  3. ClientSub将消息进行编码后发送到服务端。
  4. 服务端的ServerSub接收到消息后对消息进行解码。
  5. 找到服务器本地的对应服务进行调用,并把返回值返回给ServerSub。
  6. ServerSub对返回值进行编码并发送回消费端。
  7. clientSub对返回进行解码。
  8. 服务消费端得到调用结果。

RPC就是把2-7封装起来,然后消费端只需编码1的代码,和8的代码。

实战

这个demo仅仅使用了String类型的编解码器,也就是说只能进行String类型的数据传输。但也麻雀虽小,五脏俱全了。完成了基本的RPC通信。

代码量有点多,这里就直接上GitHub了,然后下面说说逻辑。

有三个包模块:
在这里插入图片描述
rpc-api:公共接口。
rpc-client:消费端。
rpc-provider:提供端。

使用方式:

服务端
  1. 服务端配置文件配置服务提供者。
    目录固定是类路径下的providerconfig目录下的配置文件,不包括子目录。
    在这里插入图片描述
    在这里插入图片描述
    服务端的配置文件只有2个项,分别是提供者的id,提供者的类全限定名称。
 public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException, InterruptedException {
        //参数1位端口,参数2为业务线程池的大小。
        RpcServer rpcServer = new RpcServer(5858,100);
        //启动
        rpcServer.start();
    }

结果:
在这里插入图片描述

启动消费者:
  1. 配置消费者配置文件:固定下面目录下的配置文件。
    在这里插入图片描述
    在这里插入图片描述
    启动:
public class Testst {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException {
        ClientBootStrap clientBootStrap = new ClientBootStrap();
        clientBootStrap.initClient();
        HelloService helloServiceConsumer = (HelloService) clientBootStrap.getConsumer("HelloServiceConsumer");
        System.out.println(helloServiceConsumer.sayHallo("Yehaocong"));

        HelloService helloService = (HelloService) clientBootStrap.getConsumer("HelloServiceConsumer1");
        System.out.println(helloService.sayHallo("Yehaoxian"));

    }
}

为了测试同一个客户端可以调用不同服务(ip/port不一样)提供者,我们启动两个服务端提供者,一个用5959端口,一个用5858端口。

然后测试:
在这里插入图片描述
远程调用成功。

大致原理
提供端:
  1. 服务启动时,解析配置文件,生成服务提供者,用一个map维护。这个代码在server.RpcServer#initProvider方法中。
  2. 当有消费端调用时,提供方NettyIO线程接收到数据后,转发给业务线程池调用。
    在这里插入图片描述
  3. 业务线程池解析url,找到对应的提供者对象和对应的方法,执行调用,并返回结果给消费端。
    runable.ServiceRunnable#run方法。
消费端
  1. ClientBootStrap启动时,解析配置文件,生成消费者对象,用client维护,实际上生成的是用动态代理代理过的stub对象。bootstrap.ClientBootStrap#initClient方法。
  2. 想要用某个消费者调用远程,就使用ClientBootStrap.getConsumer方法并传入消费者id,获取消费者调用。
    在这里插入图片描述
  3. 消费者调用实际上是执行stub.ClientStub#invoke方法。拼接url,进行url发送到服务端。阻塞等待结果返回,阻塞方式使用线程的wait和notify机制。
  4. 执行使用业务线程来执行,使用NettyIO线程专注IO。

消费端和服务端采用一个自定义编码器和Netty自带的LengthFieldBasedFrameDecoder解码器来解决粘包拆包问题。

测试代码:
在这里插入图片描述

结果:
在这里插入图片描述

GitHub地址:

https://github.com/YeHaocong1/rpc-demo

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值