带你手写基于 Spring 的可插拔式 RPC 框架(二)整体结构_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > 带你手写基于 Spring 的可插拔式 RPC 框架(二)整体结构

带你手写基于 Spring 的可插拔式 RPC 框架(二)整体结构

 2020/2/1 15:12:12  bianhao92115  程序员俱乐部  我要评论(0)
  • 摘要:前言上一篇文章中我们已经知道了什么是RPC框架和为什么要做一个RPC框架了,这一章我们来从宏观上分析,怎么来实现一个RPC框架,这个框架都有那些模块以及这些模块的作用。总体设计在我们的整个框架里比较重要的几个模块:rpc-procotol:既然是可插拔是框架,我们需要支持选择底层协议,这部分是通信协议相关的模块。rpc-spring:我们的框架是基于spring开发的,这个模块是将我们的一些功能和spring整合起来,比如自动注入代理bean,启动服务端server等等。rpc
  • 标签:Spring

前言

上一篇文章中我们已经知道了什么是 RPC 框架和为什么要做一个 RPC 框架了,这一章我们来从宏观上分析,怎么来实现一个 RPC 框架,这个框架都有那些模块以及这些模块的作用。

总体设计

在我们的整个框架里比较重要的几个模块:
rpc-procotol: 既然是可插拔是框架,我们需要支持选择底层协议,这部分是通信协议相关的模块。
rpc-spring: 我们的框架是基于 spring 开发的,这个模块是将我们的一些功能和 spring 整合起来,比如自动注入代理 bean,启动服务端 server 等等。
rpc-register: 注册中心模块,负责服务发现和容错。
rpc-monitor: 将注册中心的信息显示在网页上。
rpc-consumer: 消费端模块,用于测试。
rpc-provider: 服务端模块,用于测试。

  1. 注册中心模块
    对于注册中心来说,可以选择 zookeeper 和 redis,我们只实现了 zookeeper,redis 希望有能力的同学可以在 github 上完善。
    我们在使用 RPC 框架时,服务提供者和服务消费者都需要把自己注册进去,服务消费者可以将服务提供者的信息缓存到本地,通过注册节点删除的回调方法来去掉不可用的服务。
    注册中心代理了我们写 http 请求时手动写地址的功能,帮我们自动找到可用的服务。
  2. 网络协议模块
    服务消费端需要使用接口代理类的 invoke 方法将请求发给服务提供者的 RPC server(双方已经建立好了连接),RPC server 在死循环中一直等待接受请求,收到请求后调用本地的接口实现类进行处理,最后返回结
    果给服务调用端,这样就完成了一个 RPC 服务调用的过程。
    RPC 底层网络通信协议包括三个实现,netty 实现的客户端和服务端,http + Tomcat 实现的客户端和服务端,最后时 Socket 实现的客户端和服务端(性能比较低,编程练习使用)。
  3. 整合 Spring 模块
    我们整个框架是和 Spring 整合在一起的,我们在 Spring 中自定义的一些注解(类似与 Dubbo),自动为接口成代理类并注入到了 Spring 容器中,在代码中使用 @Autowired 自动注入即可使用。RPC server 的启动也要依靠 Spring 来帮我们完成。
  4. 监控模块
    通过这个模块可以查看所有服务的状态以及接口调用的相关信息。
  5. 测试模块
    rpc-provider 和 rpc-consumer 都是测试类,方便于我们对代码进行测试。

效果展示

我们先提前来看看最后最后的效果,首先说明,性能表现测试根据不同的机器和不同的网络环境可能会有所不同,下面的测试结果是基于我自己的机器的。 我的电脑最多起 2000 个并发线程,多了就 OOM 了,在公司的电脑尝试过起 10000 个并发线程,没有任何问题,下面看 2000 个并发线程的表现。

测试类

Copy
class="java">monospace !important; font-size: 14px !important; background: #f2f4f5 !important; border: none !important; border-radius: 3px !important; height: auto; color: #333333;" class="hljs">    function">public static void main(String[] args) throws Exception {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("rpc.xml");
        //并行度10000
        int parallel = 2000;

        //开始计时
        long a1 = System.currentTimeMillis();

        CountDownLatch signal = new CountDownLatch(1);
        CountDownLatch finish = new CountDownLatch(parallel);

        for (int index = 0; index < parallel; index++) {
            CalcParallelRequestThread client = new CalcParallelRequestThread(signal, finish, index,applicationContext);
            new Thread(client).start();
        }

        //n个并发线程瞬间发起请求操作
        signal.countDown();
        finish.await();

        long a2 = System.currentTimeMillis();

        String tip = String.format("RPC调用总共耗时: [%s] 毫秒", a2 - a1);
        System.out.println(tip);

    }

2000 并发 1秒多,还是比较快的。感兴趣的可以试试在自己的电脑起 1w 或者 10w 加线程测试一下。

发表评论
用户名: 匿名