目录
- 1 背景知识
- 2 RPC概述
- 3 RPC框架实现要点
- 3.1 注册中心
- 3.2 代理技术
- 3.3 序列化技术
- 3.4 RPC通信协议
- 3.5 系统IO
- 3.6 超时重试机制
- 3.7 时间轮算法
- 3.8 负载均衡策略
- 3.9 熔断限流
- 3.10 滑动窗口算法
- 3.11 限流组件
1 背景知识
单体架构
RPC产生解决的问题:
序列化是指把一个Java对象变成二进制内容(010101011010),本质上就是一个byte[]数组。
网络模块就是IO,底层已结写好了调用,开发者只需注入即可
2 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是面向服务的更高级的抽象,支持服务注册发现,负载均衡,超时重试,熔断降级等高级特性
3 RPC框架实现要点
3.1 注册中心
服务注册发现的作用
在高可用的生产环境中,服务一般都以集群方式提供服务,集群里面的IP等重要参数信息可能随时会发生变化,节点也可能会动态扩缩容,客户端需要能够及时感知服务端的变化,获取集群最新服务节点的连接信息,而这些变化要求是要对调用方应用无感知的
主流服务注册工具
Zookeeper
Consul
Nacos
…
3.2 代理技术
为什么要用代理
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
Byte Buddy本身也是基于 ASM API 实现的,是一个较高层级的抽象的字节码操作工具,通过使用 Byte Buddy,任何熟悉 Java 编程语言的人都有望非常容易地进行字节码操作。
Javassist
Javassist 使操作Java字节码变得简单,一个可以用于编辑Java字节码的类库,提供了两种级别的API:源码级别和字节码级别。如果用户使用源码级API,他们可以在不需要过多了解Java字节码规范的前提下使用它提供的基于java语言的API来编辑字节码文件。如果使用字节码级API则允许用户直接编辑字节码文件。Javassist在复杂的字节码级操作上提供了更高级别的抽象层。另外Javassist使用了反射机制,这使得运行时比ASM慢。
3.3 序列化技术
序列化的作用
在网络传输中,数据必须采用二进制形式, 所以在RPC调用过程中, 需要采用序列化技术,对入参和出参进行序列化与反序列化
优势:
解析效率
压缩率压缩后体积
扩展性
兼容性
可读性
可调试
跨语言
通用性
常见序列化技术框架
JDK原生序列化
1、JAVA语言本身提供,使用比较方便和简单
2、不支持跨语言处理,性能相对不是很好,序列化以后产生的数据相对较大
Hessian二进制
1、Hessian 是一个动态类型,二进制序列化,并且支持跨语言特性的序列化框架。
2、Hessian 性能上要比 JDK、JSON 序列化高效很多,并且生成的字节数也更小。有非常好的兼容性和稳定性,所以Hessian 更加适合作为 RPC 框架远程通信的序列化协议
Json轻量级数据交换格式
1、可读性好,方便阅读和调试,多语言支持,序列化以后的字节码文件相对较大,效率相对
不高,但对比XML序列化后的字节流更小,在企业运用普遍,特别是对前端和三方提供api
Protobuf开源,高效
1、Google 推出的开源序列库,它是一种轻便、高效的结构化数据存储格式,多语言支持。
2、速度快,压缩比高,体积小,序列化后体积相比 JSON、Hessian 小很多
3、消息格式的扩展、升级和兼容性都不错,可以做到向后兼容。
3.4 RPC通信协议
3.5 系统IO
IO选型
RPC的调用过程中涉及到网络IO的操作,一般来说网络IO往往会成为系统的瓶颈所在,而不管上层应用如何使用,底层都是基于操作系统的IO模型。
3.6 超时重试机制
3.7 时间轮算法
概念
在时钟轮机制中,有时间槽和时钟轮的概念,时间槽就相当于时钟的刻度;而时钟轮就相当于指针跳动的一个周期,我们可以将每个任务放到对应的时间槽位上。
1、每个任务会按要求只扫描执行一次,能很好的解决CPU 浪费的问题
2、秒级轮,分钟轮,小时轮除了用于检测rpc调用是否超时,也可以将定时心跳的任务添加到时间轮中,当前时间的心跳执行完后再将下一秒的心跳任务添加到时间轮中,这样就能做到每秒的定时心跳
3.8 负载均衡策略
用途
RPC Server为了高可用,可用选择做集群,因此在RPC Client端调用时要使用相应的均衡策略,这属于客户端负载均衡。
3.9 熔断限流
熔断作用
熔断器如同电力过载保护器。它可以实现快速失败,如果它在一段时间内侦测到许多类似的错误,会强迫其以后的多个调用快速失败,不再访问远程服务器,从而防止应用程序不断地尝试执行可能会失败的操作,使得应用程序继续执行而不用等待修正错误,或者浪费CPU时间去等到长时间的超时产生。熔断器也可以使应用程序能够诊断错误是否已经修正,如果已经修正,应用程序会再次尝试恢复调用操作
限流
作用
实际生产环境中,每个服务节点都可能由于访问量过大而引起一系列问题,就需要业务提供方能够进行自我保护,从而保证在高访问量、高并发的场景下,系统依然能够稳定,高效运行。
限流器的作用是用来限制其请求的速率,保护后台响应服务,以免服务过载导致服务不可用现象出现。
3.10 滑动窗口算法