(图片源自网络)java
从以前的描述,已经能够看出咱们会采用RPC over MQ的方式作底层实现,相似方法调用的通讯语义会在client和server两端的库中做封装。python
从后端实现来讲,咱们用三套后端来知足不一样的场景:mysql
一、对大中型分布式系统环境,rabbitmq是很是很是好的支撑。原本觉得须要本身作不少工做,但深刻了解rabbitmq,尤为是其支持的amqp协议,发现其实前人在不少思路方面已经栽好树了,好比一致性hash和跨机房等功能,都有相应的插件支撑。
因此,rabbitmq成为babel的第一选择,能够实现咱们规划功能的全集,咱们的SAAS平台都是使用的rabbitmq。nginx
二、对少许机器而言,redis提供了很是轻量级的队列支持,能够提供有限但必要的功能。
redis没有相似amqp这样的协议,须要手动做些封装。咱们在单机环境使用redis,尽量减小部署和运维的开销。web
三、对性能有苛刻要求的能够用zeromq后端去作tcp直连。前两种mq的方式毕竟会多几跳中转,但在路由的灵活性和通信语义的提供更丰富的选择,并且在大数据量的处理上,吞吐量和平均延时并不会比直连差不少。
但为了知足特殊环境的须要,咱们预留了zeromq的实现选择,最近因为新的需求,正在准备完成这块拼图。zeromq的缺点在于须要中央配置系统来帮忙完成路由功能。redis
每种后台实现对使用者透明,能够经过配置进行透明切换,可是有些高级通讯语义redis和zeromq不支持。sql
若是对应到web service 三要素:数据库
UDDI:传统的rpc或者SOA都是去注册中心发现远端对象,而后客户端主动推送数据到服务端。mq的方式帮咱们省却了自注册(订阅实现)和服务发现(mq本身路由)的问题。json
WSDL:目前咱们经过json的方式来描述rpc的service端,包括机房所在地,持久化,超时等等。后端
SOAP:目前使用json的方式,咱们定义了一个统一的Event对象来封装一些固定属性,其余都在一个map中。由业务代码本身去打包拆包。固然这种方式在大团队中不适合。
大量的工做能够利用mq来实现,咱们的工做主要体如今通信语义的封装。
❶ client端访问模式语义
queue语义(消息有去无回):传统的数据输送。
简单rpc(消息一去一回):传统的rpc和soa都适用于此场景。
轮询rpc(消息一去多回):一个request出去,多个response回来,适合于轮询下游节点的场景。
分布式存储rpc(一个request消息,只要有最小条件的response消息就返回):适合于分布式场景下的读写。例如三个拷贝,须要至少两份读成功或者至少两份写成功,等等。目前此方式咱们尚未用到。
❷ 消息分发语义(实际上这里的行为参考了storm的部分功能)
Shuffle:一个消息,会有多个接收者,这些接收者根据本身的资源状况去抢占同一来源的消息,达到load balance的目的。实际上咱们经过shuffle来作集群功能,省掉了LB的引入。并且性能强的拉多点,性能弱的拉少点,变相的实现了根据消费者的性能来作分发。
Sharding:与shuffle相似,也是多个consumer来分享消息,不过根据消息的key,保证在拓扑环境不发生改变的状况下,同一个key始终指向同一个消费者,为后续分布式系统的搭建打下基础
topic语义:全部消费者都会获得消息的一个拷贝。常见的mq语义
topic+shffule:一组消费者做为一个总体来订阅topic,获得全部的消息,每一个订阅团体内部经过shuffle的形式去分摊。这种很是适合用大数据环境下,有不一样类型的数据消费者,每个类型的消费者有各自的实例数。
topic+sharding:一组消费者做为一个总体来订阅topic,获得全部的消息,每一个订阅团体内部经过sharding的形式去分摊。相似于topic shuffle,只是换用了sharding这种更严格的语义。
❸ 数据的封装语义。用于指定babel上承载数据的特征,例如:
batch operation:用于指定是否进行批处理传递。
Security:暂无使用。
Compressing:指定payload压缩方法,目前只作了gzip。
机房:指定了机房所在地,框架会根据生产者和消费者的不一样自动作跨机房的处理。
持久化:指定在无消费者的状况下,是否须要持久化存储,以及最大大小。
超时:指定消息的最大有效时间,超过的消息将会被丢弃。
其余。
对于以上的通信语义,首先须要去底层的mq基础里面找到相对应的设施来作封装,好比对于queue语义做个简单举例:
而对于像rpc,轮询,以及其余功能,则须要相应的代码来支撑,好比:
response的返回能够经过client监听queue来实现
response和request的串联能够经过自定义的requestid来实现
轮询能够经过client 端等待多个消息返回,能够用condition来作同步
……
这里有很多细节,暂不在本文中进行展开了。
因为几种mq都有python和java的客户端,因此咱们工做会轻松不少,只是一样的逻辑须要写两份,好处仍是很明显的,使得咱们的系统语言无关,方便根据当前人员的技能状况来分配开发任务。
不过这里不得不吐槽python的并发,虽然有心理准备,没想到是如此之差。当使用多线程的时候,性能降低的厉害,比java要差两个数量级,因此咱们python版作了同步(多线程),异步(协程)两个版本。异步版本的性能尚可接受;咱们已经准备在build本身的异步python框架,来覆盖咱们的应用程序。
Babel的一大特点是跨机房通讯,来帮助咱们解决不一样数据中心的通讯问题,使得业务开发人员只用关心其所负责的业务便可。跨机房的通讯和本机房的通讯有所不一样:
本地机房的通讯讲究高吞吐量,rpc类访问会要求低延时。
跨机房通讯必须应对复杂的网络状况,要求数据不丢,rpc类通讯能够接受相对较高的延时。
实现上,咱们利用了federation插件,当rpc框架发现存在跨机房访问时,会自动启用相应的路由,下图是同事画的两种状况下的路由,绿线是本地调用,红线是跨机房调用。
对于业务应用而言,使用上是基本透明的,借助于mq的中转,在多机房环境下它也能够玩转除数据推送外的RPC类访问语义。
1 分布式数据计算平台
首先是咱们的私有化大数据平台warden。warden集数据采集、转换、分发、实时分析和展现等功能于一体,但愿从客户的原始网络流量中找出异常点和风险事件。
此图是一个warden分布式版本的草图:
采集的数据经过topic sharding类分配给不一样类型的消费者,好比ES writer,Mysql writer,实时分析引擎;每种消费者能够有不一样的实例数。
实时计算引擎经过sharding来分摊流量,达到scale out的效果。
rule引擎须要数据的时候一样经过简单的sharding的rpc就能够得到相应的数据了。
规则引擎的结果能够经过topic来进行再分发。
目前只有实时引擎是java的,由于性能要求苛刻,其余模块采用python开发。
上图只是个例子,来简要说明babel是如何支撑一个分布式数据计算系统的。实际的系统使用了更多的语义,也更加的复杂。不过借助于Babel的协助,整个系统在实现和运维上已经很大程度上减轻了复杂程度。
2 水平扩展的web系统
第二个例子是咱们曾经作过的SAAS平台私有化案例,是咱们早期SAAS平台的极简版本。
图画的略凌乱了些:
系统主架构是用haproxy作负载均衡,发到咱们的两台主机上。
两台主机内部彻底相同,右边主机内部组件没有画全。
每台主机有内部的nginx,load balance到本机器内部的诸多python web server 上。
python web server直接读取本地的nosql数据库。
写数据时,因为写请求sharding到两台机器上,因此咱们有个topic的service来处理nosql数据写入,保证每一个写入操做都写到两台机器上,每台机器的nosql始终存有全量的最新数据。
因为客户要求落地关系型数据库,因此经过shuffle再将写请求分散开,统一写入mysql中。
在这个系统中,咱们成功的利用babel创建了本身的一致性框架,从而避免了去使用db作数据一致性;同时因为对等的服务器架构,在部署维护上省掉了不少事情。
整个框架,咱们都准备了统一的metrics体系去作监控和报警(实际上metrics系统自己的跨机房属性反而是经过babel来实现),详尽的监视了RPC的某个环节,以前有过咱们监控的文章,这里就不重复了。