RPC通信原理

RPC概述

  RPC 是一个计算机通信协议/规范/标准。允许运行于一台计算机的程序通过网络调用另一台计算机的子程序,这种调用就像调用本地程序一样,且是一种Client/Server模式。可以实现进程间的通信,许多技术框架都是基于这种概念实现的。
  主要功能目标是让构建分布式计算(应用)更容易,是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议规范,简单来说就是像调用本地服务一样调用远程服务,对开发者而言是透明的。

RPC的优势

  • RPC框架一般使用长连接,不必每次通信都要3次握手,减少网络开销
  • PRC框架一般都有注册中心,有丰富的监控管理
  • 发布、下线接口、动态扩展等,对调用方来说是无感知的、统一化操作
  • 协议私密,安全性高
  • RPC能做到协议更简单、内容更小、效率更高
  • RPC是面向服务的更高级的抽象,支持服务注册发现,负载均衡,超时重试,熔断降级等高级特性

RPC架构设计

RPC通信原理_第1张图片

RPC时序图

Client Client Stub Server Stub Server 1.客户端调用 2.序列化 3.发送消息 4.反序列化 5.调用本地服务 6.服务处理 7.返回结果处理 8.结果序列化 9.返回消息 10.反序列化 11.返回调用结果 Client Client Stub Server Stub Server

RPC流程图

RPC通信原理_第2张图片

实现要点

一、注册中心

  • 服务注册发现的作用:在高可用环环境中,服务一般都以集群方式提供服务,集群里面的IP、端口等重要参数信息可能随时会发生变化,节点也可能会动态扩缩容,客户端需要能够及时赶至服务端的变化,获取集群最新服务节点连接信息,而这些变化要求是要对调用方无感知的
  • 主流服务注册工具:zookeeper、consul、nacos…

二、代理技术

RPC的调用对用户来讲是透明的,内部核心技术采用的就是代理技术,RPC会自动给接口生成一个代理实现,当我们在项目中注入接口的时候,运行过程中实际绑定的是这个接口的代理实现。在接口方法被调用的时候,它实际上是被生成的代理类拦截到了,这样就可以在生成的代理类里面,加入其他调用处理逻辑

  常见代理技术
  • JDK动态代理

在运行期动态的创建代理类,它是通过接口生成代理类的,与静态代理相比更加灵活,但是也有一定的限制,第一是代理对象必须实现一个接口,否则会报异常。第二是有性能问题,因为是通过反射来实现调用的,所以比正常的直接调用来得慢,并且通过生成类文件也会多消耗部分方法区空间,可能引起Full GC。

  • ASM

ASM是一个Java字节码操作框架。它能够以二进制形式修改已有类或者动态生成类。ASM可以直接产生二进制class文件,也可以在类被加载入Java虚拟机之前动态改变类行为(也就是生成的代码可以覆盖原来的类也可以是原始类的子类)。不过ASM在创建class字节码的过程中,操纵的是底层JVM的汇编指令级别,这要求ASM使用者要对class组织结构和JVM汇编指令有一定的了解。

  • CGLIB

CGLIB(Code Generation Library)是一个基于ASM的字节码生成库。其原理是动态生成一个要代理类的子类,子类重写要代理的类的所有
不是final的方法,在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。

  • ByteBuddy

ByteBuddy本身也是基于ASM API实现的,是一个较高层级的抽象的字节码操作工具,通过使用Byte Buddy,任何熟悉Java编程语言的人都有望非常容易地进行字节码操作。

  • Javassist

Javassist 使操作Java字节码变得简单,一个可以用于编辑Java字节码的类库,提供了两种级别的API:源码级别和字节码级别。如果用户使用源码级API,他们可以在不需要过多了解Java字节码规范的前提下使用它提供的基于java语言的API来编辑字节码文件。如果使用字节码级API则允许用户直接编辑字节码文件。Javassist在复杂的字节码级操作上提供了更高级别的抽象层。另外Javassist使用了反射机制,这使得它在运行时比ASM慢。

三、序列化技术

在网络传输中,数据必须采用二进制形式,所以在RPC调用过程中,需要采用序列化技术,对入参和出参进行序列化与反序列化。要考虑的问题是安全性、解析效率、压缩率和压缩后的体积、扩展兼容性、可读性、可调式性、跨语言、通用性…

  常见序列化技术框架
  • JDK原生序列化

1、JAVA语言本身提供,使用比较方便和简单
2、不支持跨语言处理,性能相对不是很好,序列化以后产生的数据相对较大

  • Json序列化

1、可读性好,方便阅读和调试,多语言支持,序列化以后的字节码文件相对较大,效率相对不高,但对比XML序列化后的字节流更小,在企业运用普遍,特别是对前端和三方提供api。

  • Hessian

1、Hessian是一个动态类型,二进制序列化,并且支持跨语言特性的序列化框架。
2、Hessian性能上要比JDK、JSON序列化高效很多,并且生成的字节数也更小。有非常好的兼容性和稳定性,所以Hessian更加适合作为RPC框架远程通信的序列化协议

  • Protobuf

1、Google推出的开源序列库,它是一种轻便、高效的结构化数据存储格式,多语言支持。
2、速度快,压缩比高,体积小,序列化后体积相比JSON、Hessian小很多
3、消息格式的扩展、升级和兼容性都不错,可以做到向后兼容。

三、通信协议

网络传输是以二进制流的方式传输的,如何做到发送方和接收方能进行高效准确的网络通信,这时候就需要通信协议了,在各网络分层中,有很多协议,有网络层的IP协议,传输层的TCP/UDP协议,应用层http、dubbo等协议,这些都有着广泛应用。

四、系统IO

  IO选型

RPC的调用过程中涉及到网络IO的操作,一般来说网络IO往往会成为系统的瓶颈所在,而不管上层应用如何使用,底层都是基于操作系统
的IO模型。

  • 同步阻塞IO
  • 同步非阻塞IO
  • IO多路复用
  • 信号驱动IO
  • 异步非阻塞IO

五、线程模型

消费方到服务端是采用同步还是异步,谁用线程多谁用线程少,线程的用做什么方式,业务线程和监听线程是否需要分开等等,这些都是需要考虑的问题。

六、超时重试机制

  在rpc调用过程中,如果有很多请求任务,这就需要遍历这些任务查看是否超时,需要定时轮训,有时长时间没有超时任务又会造成很多无意义的遍历,浪费cpu资源,同时过多的任务也会导致遍历一遍的时间会很长,轮训间隔时间也不好确定等,存在众多问题。
  其中有一种实现算法就是时间轮算法,每个任务会按要求只扫描执行一次,能很好的解决CPU浪费的问题。同时可以设置秒级轮,分钟轮,小时轮等,除了用于检测rpc调用是否超时,也可以将定时心跳的任务添加到时间轮中,当前时间的心跳执行完后再将下一秒的心跳任务添加到时间轮中,这样就能做到每秒的定时心跳

六、负载均衡策略

RPC Server为了高可用,可用选择做集群,因此在RPCClient端调用时要使用相应的均衡策略,这属于客户端负载均衡。

  • 轮训
  • 随机
  • 权重
  • 最少连接
  • 自适应

七、融断

熔断器如同电力过载保护器。它可以实现快速失败,如果它在一段时间内侦测到许多类似的错误,会强迫其以后的多个调用快速失败,不再访问远程服务器,从而防止应用程序不断地尝试执行可能会失败的操作,使得应用程序继续执行而不用等待修正错误,或者浪费CPU时间去等到长时间的超时产生。熔断器也可以使应用程序能够诊断错误是否已经修正,如果已经修正,应用程序会再次尝试恢复调用操作.

八、限流

实际生产环境中,每个服务节点都可能由于访问量过大而引起一系列问题,就需要业务提供方能够进行自我保护,从而保证在高访问量、高并发的场景下,系统依然能够稳定,高效运行。限流器的作用是用来限制其请求的速率,保护后台响应服务,以免服务过载导致服务不可用现象出现。

  • 令牌桶算法
  • 漏桶算法
  • 滑动窗口算法

你可能感兴趣的:(rpc,网络,java)