在网络通信的过程中,为了避免语义不一致的情况,我们需要在发送请求时设定一个边界,然后再收到请求时按照设定的边界对请求数据进行分割。这里的边界语义的表达,就是我们所说的协议。
RPC负责应用间通信,对性能要求高,但HTTP协议的数据包大小相对请求数据来说,要大很多,包含了很多额外字符,例如换行、回车等。 HTTP协议属于无状态协议,客户端无法对请求和响应进行关联,不能很好地进行异步处理。
定长协议是指协议头长度固定。协议头示意图如下。 2-RPC固定长度协议头.png
定长协议的协议头不能添加新参数,否则就会产生兼容性问题。例如我们设计了一个 88Bit 的协议头,其中协议长度占用32bit,然后为了加入新功能,在协议头里面加了2bit,并且放到协议头的最后。升级后的应用,会用新的协议发出请求,然而没有升级的应用收到的请求后,还是按照88bit 读取协议头,新加的2个bit会当作协议体前2个bit数据读出来,但原本的协议体最后2个bit会被丢弃了,这样就会导致协议体的数据是错的。
我们需要让协议头支持可扩展,扩展后协议头的长度就不能定长了。这样整个协议变成了三部分:固定部分、协议头内容、协议体内容。 可扩展协议的示意图如下。 2-RPC可扩展协议.png
网络传输的数据必须是二进制数据,但调用方请求的出入参数都是对象。对象是不能直接在网络中传输,所以我们需要提前把它转变成可传输的二进制,并且要求转换算法是可逆的,这个过程称为“序列化”。 根据请求类型和序列化类型,服务提供方将请求传来的二进制数据还原成请求对象,这个过程称为“反序列化”。
JSON额外空间开销比较大,对于大数据量服务意味着巨大的内存和磁盘开销。JSON没有类型,但Java属于强类型语言,这需要通过反射来解决类型问题,所以会影响性能,这样就要求服务提供者和调用者之间传输的数据量要小。
Hessian不支持Java一些常见类型,例如: Linked系列Locale类Byte/Short在反序列化时会变成Integer
对于服务提供者来说,服务的可靠性要比性能更重要,因此,我们在选择序列化框架时,更关注协议在版本升级后的兼容性是否很好、是否支持更多的对象类型、是否跨平台、跨语言、是否有很多人已经用过并且踩过坑了,其次,我们才会考虑性能、效率和空间开销。 另外序列化协议的安全也是需要考虑的一个重要因素。 综合考虑,当我们选择序列化协议时,考虑因素如下所示: 3-RPC协议选型考虑因素.png
对象要尽量简单,没有太多的依赖关系,属性不要太多,尽量高内聚。入参对象与返回值对象体积不要太大,更不要传太大的集合。尽量使用简单的、常用的、开发语言原生的对象,尤其是集合类。对象不要有复杂的继承关系,最好不要有父子类的情况。
您需要 登录 才可以下载或查看,没有账号?立即注册
使用道具 举报
本版积分规则 发表回复 回帖并转播 回帖后跳转到最后一页
小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )
GMT+8, 2024-11-24 10:03 , Processed in 0.065818 second(s), 23 queries .
Powered by Discuz! X3.5 Licensed
© 2001-2024 Discuz! Team.