RPC框架核心技术

同前几篇博文,本次针对大神分享的PRC框架核心技术进行总结分享。欢迎讨论

一、RPC框架整体架构

RPC Client  &&  RPC Server

RPC Client

1、动态代理根据lookUp信息(接口-实现-方法)动态创建出代理类,(创建代理类==RPC服务端的目标接口)。即Lookup为远端目标接口地址,创建调用目标接口代理。

2、上下文管理主要为标识每个请求的sessionID,保证server端返回的结果找到对应的上下文。例如同时ABC三个请求从客户端发送到server去请求,上下文就用来标识server返回的ABC response对应客户端发来的ABC request。

处理好client的请求数据后,经过序列化、经由两端统一的协议,传输到server端,进行反序列化操作解析出目标接口、参数等信息,执行invoke调用后,将结果再次序列化传输。

RPC Server

1、分发器,将请求分发到sever实例(负载策略&容错)

2、过滤器,统一拦截,在server方法执行前后进行链路调用统计、超时统计等操作

3、线程模型,下面深入总结。

核心流程

1、创建接口代理类:从客户端开始,利用动态代理创建server目标接口代理

2、序列化:将入参对象序列化

3、协议组装:将序列化方式、协议版本、协议类型、方法签名等信息组装成一个协议包,交付给传输层进行发送

4、传输,server协议:传输层将协议包发送到sever端,server端将协议包解析,从中取出接口签名、入参对象字节流信息

5、server反序列化:反序列化操作,找出接口实现类(server端真实的服务实现),invoke执行目标方法

6、server将结果序列化:Server端将返回结果按照同样的序列化方式进行序列化操作。

7、server组装协议:同样,将序列化方式、协议版本、协议类型、方法签名等信息组装成一个协议包,发送给client

8、client解析协议,反序列化结果:Client接收sever返回的协议包,经过解析协议包中返回结果流,反序列化操作,得到RPC方法调用结果

这就是完整的一个RPC请求流程 (下次问终于不至于provider、consumer、zk注册中心这码事儿了)

RPC架构和流程不难看出,RPC核心技术包括:动态代理、序列化、协议、通讯(netty)、注册中心几块技术。动态代理就不多说了,可看上周的博文:JDK、CGLib、Javassist实现动态代理。本次重点讨论序列化反序列化、传输协议、server端的线程模型

二、序列化&反序列化

序列化载体:

xml:可扩展标记语言,自定义节点schema含义;但传输太多额外无用的数据(schema、节点解析)

Json:kv结构,易扩展

二进制字节流:紧凑,无额外多余数据,减少传输占用带宽;但字节顺序是固定的,例如user对象,1-8字节存储userId,8-16存储username;如果删减user属性,序列化反序列化时数据则对不上。则需要对属性添加tagId标识,tagID(sortedId)=1,则标识userId,tagId=2标识username;type标识属性类型(类型可知则知道对应占字节长度),value标识属性值;(其实这里用tagID标识属性名,根据属性名采用反射即可得到字段类型、长度信息;可能考虑效率,直接采用key标识)

这就定义好了采用字节流来序列化传输对象。

三、协议

常用的通讯协议、数据传输格式、底层传输协议、序列化方式、应用实现整理如下:


 而公司自研的RPC框架采用自定义协议包。考虑到非开源,简单介绍,思路一致,非实际实现。

协议一般包括定长包头(公共属性)和变长包体(业务数据)组成。例如

1byte(版本号)|1-4byte(协议总长度)|5-8byte(序列号)|9byte(服务编号)|10byte(消息体类型)|11byte(压缩;算法)|12byte(序列化规则)

消息头总长度:12 byte

协议总长度=消息头总长度+消息体总长度(不含分界符)

 四、总结

序列化、协议(自定义)还需结合代码看实现逻辑,架构部同事提供的丰厚土壤,不吸收就辜负了。

猜你喜欢

转载自blog.csdn.net/daybreak1209/article/details/80509964