**章节讲到【《为什么要实现服务化,解决什么问题?》】第二章讲到“微服务服务粒度的选择”】中上一篇文章讲到【“为什么说要修微服务架构,先修RPC框架?”】通过上一篇文章的介绍,大家知道要实现微服务,首先要修RPC框架。RPC框架。调用者]和[服务提供者]屏蔽了各种复杂性:(1)让调用者感觉像是在调用一个本地函数(2)让服务提供者感觉像是在实现一个本地函数来实现整个RPC框架的服务和它是分为client部分和server部分:RPC-client部分流程如上图所示,需要序列化和反序列化(上图中的1、4),需要发送字节流和接收字节流(在上图2、3中)。通过上一篇的用户调查:78%的读者->继续聊RPC框架的技术细节14%的读者->聊聊微服务的其他实践7%的读者->别聊微服务了,聊聊关于最终一致性,那么根据大部分读者的意见,今天就来聊一聊RPC的技术细节。本文首先讨论RPC-client部分的【序列化与反序列化】的实现细节(作者并非这方面的专家,如有不妥之处欢迎指正,有建设性的意见请留言分享更多朋友在下一章)。1、为什么序列化工程师通常使用“对象”来操作数据:classUser{std::Stringuser_name;uint64_tuser_id;uint32_tuser_age;};Useru=newUser("shenjian");u.setUid(123);u.设置年龄(35);但当数据需要存储(固化存储、缓存存储)或传输(跨进程网络传输)时,“对象”就没那么好用了,往往需要将数据连续不断地转换成二进制字spaceThrottle,一些典型的场景有:(1)数据库索引的磁盘存储:数据库索引在内存中是b+树或者hash的格式,但是这种格式不能直接存储在磁盘上,所以需要b+树stored或hash可以转换成连续空间的二进制字节流,才可以存储到磁盘上。(2)缓存的KV存储:redis/memcache是??KV类型的缓存,缓存中存储的值必须是连续空间的二进制字节流,不能是User对象的网络传输(3)数据:数据socket发送的必须是连续空间的二进制字节流,不能是对象。过程以“二进制字节流”形式存储和传输数据。这个过程的逆过程称为反序列化。2.如何连载这是一个很细的问题。如果让你把“对象”转换成字节流,你会怎么做?一种很容易想到的方法是带有自描述特征标记语言的xml(或json):指定转换规则,发送端可以轻松序列化将User类的一个对象转化为xml,服务端收到xml二进制流后,也很容易将其作用域序列化为User对象(尤其当语言支持反射时,就更容易了)。第二种方法是自己实现二进制协议进行序列化,或者以上面的User对象为例,可以设计这样一个通用的协议:(1)前4个字节代表序列号(2)后面的4个字符序号段表示key的长度m(3)接下来的m个字节表示key的值(4)接下来的4个字节表示value的长度n(5)接下来的n个字节表示value的值value(6)像xml一样递归,直到描述整个对象上的User对象,可能被这个协议描述为:(1)***line:4字节的序号(设置0表示类name),classname的长度为4个字节(长度为4),接下来的4个字节为类名(“User”),共12个字节(2)第二行:序号为4字节(1表示***属性),属性长度为4字节(长度为9),接下来的9字节为属性名(“user_name”),属性value长度为4个字节(length为8),属性值8个字节(值为“shenjian”),共29个字节(3)第三行:4个字节为序列号(2表示第二个属性),4字节为属性长度(长度为7),接下来的7字节为属性名(“user_id”),属性值长度为4字节(长度为8),属性值为8字节(值为123),一共27字节(3)第四行:序号为4字节(3表示第三个属性),属性长度为4字节(长度为8),接下来8个字节为属性名("user_name"),属性值长度为4个字节(length为4),属性值为4个字节(值为35),共24个字节。整个二进制字节流一共有12+29+27+24=92个字节。实际的序列化协议需要考虑的细节远不止于此,例如:强类型语言不仅要还原属性名、属性值,还要还原属性类型;对于复杂对象,不仅要考虑普通类型,还要考虑对象嵌套类型。不过,序列化的思路是类似的。3.序列化协议应该考虑哪些因素无论是使用成熟的协议xml/json还是自定义的二进制协议来序列化对象,在设计序列化协议时应该考虑哪些因素?(1)解析效率:这应该是序列化协议首先考虑的因素,比如xml/json解析起来比较费时,需要解析doom树,二进制自定义协议解析效率很高(2)压缩率、传输效率:同一个对象,传输xml/jsonxml标签数量多,信息有效性低,二进制自定义协议占用空间相对较小(3)可扩展性和兼容性:是否可以方便的添加字段,老版本客户端是否需要强制升级是需要考虑的问题。xml/json和上面的二进制协议都可以很方便的扩展(4)可读性和调试性:这个很好理解,xml/json的可读性比二进制协议好很多(5)跨语言:上面两个协议是跨语言的,有些序列化协议和开发语言密切相关,比如dubbo的序列化协议只能支持JavaRPC调用(6)通用性:xml/json通用性很强,有很好的第三方解析图书馆。解析每种语言非常方便。上面定义的二进制协议虽然可以跨语言,但是每种语言都需要写一个简单的协议客户端(7)欢迎大家补充...4、业界常见的序列化方式(1)xml/json:解析效率差,压缩性差速度;良好的扩展性、可读性和通用性(2)thrift:没用过,欢迎补充(3)protobuf:Google出品,一定是精品。各方面都不错。强烈推荐。属于二进制协议,可读性有点差,不过也有类似to-string的协议,可以帮助调试问题。(4)Avro:没用的,欢迎补充(5)CORBA:没用过,欢迎补充(6)mc_pack:懂的就懂,不懂的就不懂它。我是2009年用的,据说各方面都超过了protobuf。同学们可以说说现状(7)...5.RPC-client部分,稍后公布。除了序列化和反序列化,还需要发送字节流和接收字节流。下一篇文章将介绍这部分内容。RPC-client中数据的发送和接收远比序列化和反序列化复杂。涉及“连接池、负载均衡、故障转移、队列、超时、异步、上下文回调管理”等技术。详情我们将在下一篇文章中进行交流。文章转载自微信公众号《建筑师之路》