最近更新

360消息系统RPC基础库迭代 2015-01-03

引文:

    消息系统内部各服务的通信,是依赖于RPC调用串联起来的。RPC框架的易用性,性能,开销决定了整个系统的开发的灵活性,整体性能和负载上限。因此对于这样一个基础库,硬性要求一定是稳定高效易用的,一旦整个系统使用,除非必要不做影响应用层的修改。但由于项目在启动时,go语言本身还没有成型的开源方案,先后开发3个版本,才完善成型。

    消息系统的rpc框架的迭代,可以说是系统通信模型设计的一个缩影,走完了能走的弯路。。。(填坑)他的起点或者说设计思路,就是简单易用,迅速迭代完成系统原型。它在上线初期很好的完成了使命,但后期随之而来的并发通信压力,业务级别的策略已经无法改善通信瓶颈,必须对底层通信库做彻底改造,并升级系统服务所有接口到新通信框架。3次迭代带来工作量有多大和繁琐,让我想起当年在手机微博做v4重构的经历,只不过当年是我设计实现web框架,由朱陶和小天天组织迁移逻辑,重新封装接口,上线,最大痛苦由迁移团队承担。这一次由自己来推进多次从设计到上线的全套工作,看来,出来混总是要还的~。

    下面来谈谈具体迭代过程。

浅谈rpc

    一个RPC库的设计(基于TCP),牵扯到几个基本的概念:用户调用,传输编码,信道利用。
    用户调用:
        按过程分为:调用者发起请求(call),等待远端完成工作,获取对端响应,三个过程。
    根据调用方式还可分为:  
        同步调用:发送请求,等待结果,结果返回调用方。
        异步调用:发送请求,用户立刻拿到请求handler,通信和调用交给底层框架处理,用户可以处理其他逻辑,再通过之前返回handler来直接获取处理结果。
        同步通知:发送请求,数据送达到对方,无需等待结果,返回ack response到调用方,释放同步请求。
    传输编码:
        即对用户的请求request与服务端的响应response做encode与decode。即将请求数据结构,与响应数据结构序列化后在网络中总传输。比如常见的protobuf,msgPack,bson,json,xml,gob等。如果要对编解码分类,可能分为文本型和二进制型,比如json,xml这些属于文本型,其他几种属于二进制型。在编码方式实现上,同一种编码在实现效率上可能有区别,我们消息系统主要使用了go语言原生的gob编码(相比较网络io,编码效率与业务层易用性权衡下的选择)。具体编码的选择上,因项目而异,对于rpc通信框架来说,只关心编解码实现过程中牵扯到与rpc框架交互的接口。牵扯到两个相关于性能的细节:内存复用,与对象复用。
    信道利用:
        对于一个基于tcp的框架,主要牵扯两个问题,一个是长短连接,连接复用策略,与连接管理。