babel: yet another rpc, but far beyond rpc(上)
这几年工作下来,越来越体会到communication的重要性,无论是从技术层面还是工程组织层面。在这方面的投入,对工作效率、产品质量等等方面都会有很好的加强。
尤其是我们岂安的技术团队从开始就处于人力匮乏的状态,又同时要覆盖SAAS和私有化大数据解决方案两条迥然不同的研发线路,矛盾比较突出。所以,从开始的时候就想着去建立一套自己的通讯基础设施,来满足不同业务场景下的各种需求,于是催生了这朵RPC领域的奇葩。
冠名以babel,纯属个人在初始阶段的勃勃雄心,希望能尽可能的消弭不同系统组件间的通讯细节,让我们这帮三流的程序员也能做出二流的系统:
要解决python和java的问题,各语言对等。我们的系统有大量跨语言的交互,需要尽量减少通讯开销。这个是RPC的基本功。
要能简单的管理和监控。这个是RPC良好运维,进化到service层面所需要的。
最好还能兼顾离线数据分析过程中的数据组织功能。以数据为核心的公司这点其实很重要。
可以兼顾大规模集群环境和小集群环境(甚至是单机)。
要解决跨数据中心的问题。风控SAAS有SLA方面的变态需求,需要部署到客户最后100米处,这也是刚需。
不光是通信,还要能做好持久化、负载均衡、动态伸缩等等其他功能,这个是衡量分布式系统成功与否的重要指标。
轻。
本文后续部分会先在技术背景方面闲聊一会,讲讲为啥要造轮子;然后会介绍一下我们这个简单又独特的RPC的实现部分,以及在我们岂安公司的实际例子;最后再探讨一下基于技术手段来影响整个工程组织方式。
RPC漫谈
rpc这个领域其实已经是历经好几十年的发展了:
最早是corba,用来解决跨语言跨平台的数据交互,新一点有ICE,算是更加完整的框架;
也有平台、语言相关的RPC,比如DCOM,RMI等等;
十多年前web service为代表的SOA(service本质上是更规范化的RPC)大火,有一整套以xml为基础的框架,伴随着企业应用的蓬勃发展,越来越重。学术界也做了很多脱离实际的工作;
几年前开始回归简单,有protocol buffer和thrift,虽然两者本质上是序列化工具,但也提供了简单的rpc实现,实际上有很多系统是基于thrift框架来实现;另外restful风格也开始逐渐盛行;
最近由于分布式系统成为越来越明显的特征,多年前SOA方面的很多内容渐渐开始有实际价值,一番改造后再度开始登场,微服务现在是业界的热点,也必将成为今后的标准;
国内外很多大型互联网公司也开始作自己的SOA平台,之前在携程的老板就建了一套面向.NET和java的现代化的SOA框架。开源方面,netflix走在前面,阿里的dubbo也应该是国内的翘楚。
异步持久化通信
需要先澄清的是,抛开SOA,微服务,web service,rpc等等各种名词,本质上其实是在讲通信,只是表层的包装方式不同。
而通讯有两个维度可以切割:同步异步,持久化。
同步非持久化通讯:传统的rpc属于这个范畴,client和server两方必须同时存在,一问一答。这种是最普遍的形式,尤其在前端。
异步持久化通讯:传统的mq属于这个范畴,server不需要保持在线,client发了就跑,由mq系统作中间缓存。mq的语义其实系统后端是更典型的通讯方式。
异步非持久化通讯:这种没有什么意义。
同步持久化通讯:这种目前市面上还比较少,但也是有意义的,会是很好的补充。
我们对RPC的需求实际上需要涵盖1、2、4三个方面。一般的做法是使用独立的rpc和mq系统,再定制开发。最终,我们选择基于现有系统改一个轮子。
自带路由和位置透明的通信
通信很重要的一点是参与对象的定位,现有的从简单到复杂有不同的模式:
写死对端ip地址。开发最简单,后期运维是噩梦;
通过配置系统来配置ip。需要开发相应的配置服务,可以集中管理,但仍需要手动管理位置信息;
自动注册和发现。类似web service中UDDI的概念,现在也有很多开源组件,需要集成;
上述三点是传统rpc的定位方式,mq的定位方式更加灵活。
我们的角度,希望是有如下的通讯模型:
由中央的RPC框架统一管控消息的路由、持久化。
每个消息的生产者和接收者只需要配置虚拟名称,实现与ip地址的完全解耦。
支持消息的对话和群发功能,但不需要消息发送端作多余的工作,由RPC框架来支撑。
RPC框架类似一个邮局的功能,每个实体只需要打通跟其临近的节点(邮箱)就可以通讯。所以从运维的角度,只需要开放一个单独的端口,每台应用服务器(生产者)也只需要绑定一台框架服务器(邮箱地址)。
只有实现这样的通讯框架,我们才能做到:
所有节点对等,不需要额外的配置,方便部署和迁移。
所有节点只需要和框架节点通信,大大降低网络复杂度,并提升安全性。
所有的通讯都集中起来,可以统一管理。
实际上,我们是借助现有的mq开源软件来帮助我们实现这一点。
没有灵魂的SOA
RPC,在规范化到一定程度后,可以成为service,这个是在中大型企业的常规武器。
而service,有几个组件必不可少,借用web service的术语:
UDDI:统一的注册中心
SOAP:消息交换载体,作为网络通信的序列化和反序列化支撑
WSDL:服务的规范化描述
其实,这几个本质上是以XML为基础,包括后续的各种功能特性,以及学术界叠加的什么semantic web等等。
XML本身实际上是整个SOA的灵魂,它才是建立babel tower的基石。然而,由于工程化方面的困难,大家往往绕过。比如,消息采用json/pb等方式,其实完全是两个层次的玩意,这就导致现有的各种SOA系统都是没有魂的系统,只能起到通信承载的功能。
笔者之前两家公司所遇到的就是两个很好的典型:
第一家公司,个人一直评价为好体系配上烂技术。公司有一套C++的RPC框架,框架本身比较普通。我最诟病的是没有注册中心,所以配置上会比较繁琐僵硬。
但是,他在消息内容的定义上颇下功夫,所有消息全部由统一的唯一的xml定义,每个字段都有背后指定的含义,这个在跨部门跨系统的交流上起着至关重要的作用。
这一套虽然与技术无关,但可以看出其作为数据驱动公司的底蕴,估计还是由数据部门驱动的原因。当然,由于底层技术支撑不够,所以整套执行到后来良定义的消息也只有很少人才能明确,失去了原有的意义。第二家公司,有一套现代化的SOA系统,仅从技术层面去讨论,没什么可挑剔的。这套系统有注册中心,有自己的序列化框架,有服务描述和代码生成等功能,算是完备,但也仅限于技术层面的完备。
因为是技术人员推动的系统,所以对业务的渗透不够,虽然有了一套底层支撑,但是整个消息的定义是没有很好的定义的(非xml这种语义型的定义),所以虽然在技术上取得了成功,但是对业务的推进没法起到决定性的作用。
两个例子正好相反,可以看出两家公司驱动力的不同,以及管理与技术之间可能的微妙关系。
之所以写这一段,是因为之前也提到XML才是babel tower的基石,但其实基本没人做到,我们也做不到。但由于我们厚着脸皮打了babel的名号,所以还是需要澄清一下,甚至,我们走的更加极端——干脆连序列化消息的schema定义也扔掉了,服务定义和消息组织全部用松散的json,一方面是出于减少开销(仅适合我们当前这种微型团队的场景),另一方面,也是没想好怎么玩,所以只是留下升级的空间,暂不触及。
所以说,我们的RPC也是失了魂的,仅仅是对通信的实现和封装上提供一些简要的支撑,覆盖的是通信语义,业务语义上没有涉及。