大致思路

一般情况下,RPC框架不仅要提供服务发现功能,还要提供负载均衡、容错等功能。这样

的RPC框架才算真正合格的。

最简单RPC框架图

RPC框架有什么作用_rpc

从上图我们可以看出:

服务提供端 server向注册中心注册服务,服务消费者 CIient通过注册中心拿到服务相关信息,然后再通过网络请求服务提供端server。

Dubbo框架图

RPC框架有什么作用_RPC框架有什么作用_02

详细设计
框架图

RPC框架有什么作用_RPC_03

调用关系说明:

  1. 服务容器负责启动‘加载‘运行服务提供者。
  2. 服务提供者在启动时‘向注册中心注册自己提供的服务。
  3. 服务消费者在启动时‘向注册中心订阅自己所需的服务。
  4. 注册中心返回服务提供者地址列表给消费者‘如果有变更‘注册中心将基于长连接推送变更数据给消费者。
  5. 服务消费者‘从提供者地址列表中‘基于软负载均衡算法‘选—台提供者进行调用‘如果调用失败‘再选另—台调用。
  6. 服务消费者和提供者‘在内存中累计调用次数和调用时间‘定时每分钟发送—次统计数据到监控中心。

参考上面这张图,简单说一下设计一个最基本的 RPC框架的思路或者说实现一个最基本的RPC框架需要哪些东西:

注册中心

注册中心首先是要有的。比较推荐使用zookeeper作为注册中心。

zookeeper为我们提供了高可用,高性能,稳定的分布式数据—致性解决方案地通常被用于实现诸如数据发布/订阅,负载均衡,命名服务,分布式协调/通知,集群管理,Master 选举等功能。并且地zookeeper将数据保存在内存中地性能是非 常棒的。

网络传输

既然我们要调用远程的方法.就要通过发送网络请求来传递目标类和方法的信息以及方法的参数等数据到服务提供端,这样就必须需要高效稳定的网络传输了。

网络传输我们选择,基于 NIO的网络编程框架 Netty。

简单了解下Netty:

  1. Netty是一个基于NIO模型的cient-server(客户端服务器)框架,使用它可以快速简单地开发网络应用程序。
  2. Netty极大地简化并简化了 TCP和 UDP套接字服务器等网络编程。并且性能以及安全性等很多方面甚至都要更好。
  3. 支持多种协议如 FTP,SMTP,HTTP以及各种二进制和基于文本的传统协议。

 

序列化与反序列化

要在网络传输数据就要涉及到序列化。

因为网络传输的数据必须是二进制的。因此‘我们的 Java对象没办法直接在网络中传输。为了能够让Java对象在网络中传输我们需要将其序列化为二进制的数据。我们最终需要的还是目标Java对象‘因此我们还要将二进制的数据“解析”为目标 Java对象‘也就是对二进制数据再进行—次反序列化。

JDK自带的序列化‘只需实现 ava. .seralzable接口即可‘不过这种方式不推荐‘因为不支持跨语言调用并且性能比较差。

现在比较常用序列化的有hessian,kyro,protostuff......。

动态代理

在RPC框架中,动态代理也是需要的。

动态代理概念:

我们给某—个对象提供—个代理对象,并由代理对象来代替真实 对象做—些事情。你可以把代理对象理解为—个幕后的工具人。

举个例子:我们真实对象 调用方法的时候‘我们可以通过代理对象去做—些事情比如安全校验,日志打印等等。但是,这个过程是完全对真实对象屏蔽的。

动态代理在 RPC框架中的作用:

RPC的主要目的就是让我们调用远程方法像调用本地方法一样简单,我们不需要关心远程方法调用的细节比如网络传输。

怎样才能屏蔽程方法调用的底层细节呢?

答案就是动态代理。简单来说,当你调用远程方法的时候,实际会通过代理对象来传输网

络请求。

负载均衡

负载均衡也是需要的:

举个例子:我们的系统中的某个服务的访问量特别大,我们将这个服务部署在了多台服务器上,当客户端发起请求的时候,多台服务器都可以处理这个请求。那么,如何正确选择处理该请求的服务器就很关键。假如,你就要—台服务器来处理该服务的请求,那该服务部署在多台服务器的意义就不复存在了。负载均衡就是为了避免单个服务器响应同—请求‘容易造成服务器岩机崩溃等问题‘我们从负载均衡的这四个字就能明显感受到它的意义。

传输协议

我们还需要设计—个私有的 RPC协议,这个协议是客户端 (服务消费方)和服务端 (服务提供方)交流的基础。

简单来说:通过设计协议,我们定义需要传输哪些类型的数据 .。并且还会规定每一种类型的数据应该占多少字节。这样我们在接收到二进制数据之后.就可以正确的解析出我们需要的数据。 这有—点像密文传输的感觉。

通常—些标准的 RPC协议包含下面这些内容:

  1. . 魔数:通常是 4个字节。这个魔数主要是为了筛选来到服务端的数据包 ‘有了这个魔数之后‘服务端首先取出前面四个字节进行比对‘能够在第—时间识别出这个数据包并非是遵循自定义协议的‘也就是无效数据包‘为了安全考虑可以直接关闭连接以节省资源。
  2. 序列化器编号 :标识序列化的方式‘比如是使用 Java自带的序列化‘还是 json‘ kyro等序列化方式。
  3. 消息体长度 : 运行时计算出来。
总结
  1. 实现—个最基本的 RPC框架应该至少包括下面几部分:
  2. 注册中心 :注册中心负责服务地址的注册与查找相当于目录服务。
  3. 网络传输 :既然我们要调用远程的方法就要发送网络请求来传递目标类和方法的信息以及方法的参数等数据到服务提供端。
  4. 序列化和反序列化 :要在网络传输数据就要涉及到序列化。
  5. 动态代理 :屏蔽程方法调用的底层细节。
  6. 负载均衡 : 避免单个服务器响应同—请求容易造成服务器岩机,崩溃等问题。
  7. 传输协议 :这个协议是客户端(服务消费方)和服务端(服务提供方)交流的基础。