天天看点

最近分布式系统开发小结

用最简单的语言梳理一下最近十天做的分布式系统模块的开发。这是一个还在开发中的项目,配图也是设计原图。希望能更多地从开源项目里汲取营养,一边实战,一边积累。

最近在设计和开发一个分布式系统的流式处理模块,整个系统用于跨集群、跨机房搬运不同数据源内的数据到另一份或多份数据源上,包括hdfs、mysql、mongodb、ftp等。功能比较像hadoop的sqoop,但是能扩展支持更多的数据源,且本身是个集群部署,不像sqoop需要依赖hadoop的mr。

我们整个cluster的资源管理借助mesos来完成,由自己定制的mesos scheduler向mesos master申请可用的资源,具体把数据搬运的任务分发到mesos slave的executor上,而我主要负责的就是slave模块,包括slave上executors的实现、不同slave上executor之间的通信、消息处理、每次task的容错和可靠性等内容。

一共有三种executors,简单分为input、cache、output,直观理解input就是读取数据源,cache用于从input到output的缓存,output是获取cache里的数据,向目标数据源

导出数据。

executor具体涉及到下面一些问题:

1.      executor之间的网络通信

2.      数据流里每个tuple在网络中的序列化、压缩等流通问题

3.      消息队列

4.      其他:多线程、双队列缓存设计、状态记录等

我们还具体考虑了input、cache、output分别挂掉要怎样继续去执行整个数据流的搬运,这里涉及到了把一些描述和状态更新统一写到zookeeper里,需要cache模块做对消息的钝化/checkpoint/journallog。

整个模块的设计图如下:

最近分布式系统开发小结

netty有很优雅的设计,封装了java的网络nio接口,还重写了channelbuffer。利用netty框架,executors之间的通信简化为下面这样的模式:

最近分布式系统开发小结

我今天参考了storm0.9.0里新增加的netty模块,优化了下slave模块里的netty部分。其实storm里的netty部分蛮简单,比较我们想要做的实现更简单,主要体现在两处:

1.  cache作为netty server,既要接收inputclient的写,又要接受outputclient的读请求。

2.  cache交互的queue不是一个java concurrent包里的某个queue容器,而是一个轻量级的workqueue:beanstalkd

采用的是beanstalkd,每个tube对应一个output,之前的博文介绍了beanstalkd。

数据的序列化和反序列化,本来想要使用kryo这样的在开源软件中经常见到的高效工具。后来参考了storm里的taskmessage结构,发现不如直接把pojo设计成一个byte[],自己定义一下byte数组的结构来的更高效。毕竟一个java对象转bytes,再高效也不如直接拼byte[]快。

数据压缩方面snappy有很快的压缩速度。

其实我们的input比较像storm的spout,cache和output比较像bolt,但是又没有storm里的shuffle grouping等机制,input与cache是指定的一对一的,cache与output是一对多,而这些对应关系会在物理执行计划模块里生成。

在storm的设计里,参考了它的acker。storm能保证消息不会丢失,并且每条消息都会被完整处理,即这个tuple以及由这个tuple所导致的所有的tuple都被成功处理。而一个tuple会被认为处理失败了如果这个消息在timeout所指定的时间内没有成功处理。能做到这点,他的acker起到了很重要的作用。(arker模块的设计和源码分析)

我们打算做一个acker模块,但消息的执行状态和更新会写在znode上,让arker模块与zk打交道,然后去更新beanstalkd里已经reserve了的job。有时间还要把storm的源码和模块仔细读读,尽量能多参考一些设计思路。

(全文完)