RPC框架

60 阅读9分钟

RPC框架

RPC概述

分布式节点通信

image.png

跨节点通信方式

  • Socket:原生socket编程。
  • RMI:远程方法调用,只用于Java,可以把RMI看作是用java语言实现了RPC。
  • 标准公有协议:利用标准的公有协议进行跨节点服务调用,例如:http+xml,RESTful+json,webs-ervice等。
  • RPC:是一个计算机通信协议/规范/标准,允许运行于一台计算机的程序调用另一台计算机的子程序。就像调用本地程序一样,且是一种Client/Server模式。

RPC的作用及优势

RPC 的主要功能目标是让构建分布式计算(应用)更容易,是一种通过网络从远程计算机程序上请求服务, 而不需要了解底层网络技术的协议规范,简单的来说就是像调用本地服务一样调用远程服务,对开发者而言是透明的。

为什么用RPC

  1. 分布式设计
  2. 部署灵活
  3. 解耦服务
  4. 扩展性强

常见RPC框架

  1. Dubbo:阿里巴巴,java
  2. gRPC:Google,多语言
  3. Thrift:Facebook/apache,多语言
  4. Spring Cloud:不仅仅是RPC,更多的是微服务架构下的一站式解决方案

RPC的优势

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

RPC架构设计

image.png

服务端

  1. 服务注册
  2. 网络传输
  3. 协议解码
  4. 反序列化(解码)
  5. 调用模块
  6. 故障检测
  7. 序列化(编码)
  8. 协议编码
  9. 线程模型

客户端

  1. 服务发现
  2. 路由
  3. 负载均衡
  4. 超时重试
  5. 限流熔断
  6. 序列化(编码)
  7. 协议编码
  8. 网络传输
  9. 协议解码
  10. 反序列化(解码)
  11. 线程模型

注册中心

  1. 保存(服务名称,ip,port,接口列表元数据信息)
  2. 客户端主动订阅服务,当客户端订阅的服务有变化时主动推送给客户端。
  3. 定时向客户端发送心跳检测
  4. 服务单发布服务信息
  5. 定时向服务端发送心跳检测

RPC框架架构分析

RPC调用时序

image.png

RPC流程图

image.png

RPC框架实现要点

注册中心

服务注册发现的作用

在高可用的生产环境中,服务一般都以集群方式提供服务,集群里面的IP 等重要参数信息可能随时会发生变化,节点也可能会动态扩缩容,客户 端需要能够及时感知服务端的变化,获取集群最新服务节点的连接信息 ,而这些变化要求是要对调用方应用无感知的

主流服务注册工具

  1. Zookeeper
  2. Consul
  3. Nacos

注册中心数据结构

image.png

代理技术

为什么要用代理

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

常见代理技术

JDK动态代理

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

ASM

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

CGLIB

image.png

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

bytebuddy

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

Javassist

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

image.png

序列化技术

序列化的作用

在网络传输中,数据必须采用二进制形式, 所以在RPC调用过程中, 需要采用序列化技术,对入参和出参进行序列化与反序列化

序列化选型要点

  1. 解析效率
  2. 压缩率、压缩后体积
  3. 扩展性、兼容性
  4. 可读性、可调试
  5. 跨语言
  6. 通用性

常见序列化技术框架

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

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

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

开源,高效

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

网络

RPC通信协议

image.png

image.png

系统IO

IO选型

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

IO模型

  1. 同步阻塞IO
  2. 同步非阻塞IO
  3. IO多路复用
  4. 信号驱动IO
  5. 异步非阻塞IO

线程模型

image.png

异步如何实现 常用的方式就是Future 方式,它是返回 Future 对象,通过GET方式获取结果;或者采用入参为 Callback 对象的回调方式,处理结果。

image.png

image.png

超时

超时重试机制

image.png

问题

有很多无意义的遍历操作开销,浪费CPU

时间轮算法

概念

在时钟轮机制中,有时间槽和时钟轮的概念,时间槽就相当于时钟的刻度;而时钟轮就相当于指针跳动的一个周期,我们可以将每个任务放到对应的时间槽位上。

image.png

image.png

优势

  1. 每个任务会按要求只扫描执行一次,能很好的解决CPU浪费的问题
  2. 秒级轮,分钟轮,小时轮

除了用于检测rpc调用是否超时,也可以将定时心跳的任务添加到时间轮中,当前时间的心跳执行完后再将下一秒的心跳任务添加到时间轮中,这样就能做到每秒的定时心跳

路由,负载均衡

用途

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

image.png

负载均衡策略

  1. 轮训
  2. 随机
  3. 权重
  4. 最少连接
  5. 自适应

熔断,限流

熔断

作用

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

image.png

限流

作用

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

image.png

滑动窗口算法

image.png

限流组件

image.png