最近因为空闲时间有一些,所以去看了不少开源项目,大部分东西如果看过不记录下来,其实还是相当于没看,所以想想还是有必要摘要记录一下。
首先是去了解了
zookeeper这个项目,基于paxos算法的分布式服务组件,同事对此有非常深入的研究和介绍,具体可以看我们的
团队Blog。令我感慨的是这么一个非常难以理解的算法,却用一个简单的树状目录模型表达出来,并且在这个模型的基础上衍生出种种应用:集群感知、分布式锁、分布式队列、分布式并发原语等等,具体可以看文档给出的
recipes。在实现这些应用的时候,突出强调的是避免网络风暴,例如分布式锁的实现,竞争创建子节点,节点序列号最小的获取锁,其他节点等待,但是等待在什么条件上是有讲究的,如果所有节点都等待最小节点的删除事件,那么当最小节点释放锁的时候,就需要广播消息给所有其他等待的节点;换一个思路,如果每个等待节点只是等待比它序列号小的节点上,那么就可以避免这种广播风暴,变成一个顺序唤醒的过程。因此尽管有了zookeeper帮助实现分布式这些服务,但是要实现好仍然有一定难度,具体可以参考官方例子。我本来萌生了基于zookeeper实现一套封装好的类似j.u.c的服务框架,后来在邮件列表发现已经有人搞了这么一个基础类库放在github上:
https://github.com/openUtility/menagerie 。不过我没有继续深入了,有兴趣的朋友可以瞧瞧。
然后又去看了我们淘宝开源的
TimeTunnel。TimeTunnel你可以理解成一个消息中间件,它整个设计跟我们的产品相当接近,但是两者的目的完全不同,tt强调的是高吞吐量,而notify强调的则是可靠性。TT的通讯层直接采用Facebook的thrift,并且利用zookeeper做集群管理和路由。TT的代码质量很好,有兴趣可以拉出来看一下,并且对zookeeper的应用也是一个典型的案例。TT在高可用性上的方案也很有特色,所有的服务器节点形成一个环,两两相互主辅备份,一个节点挂了,后续节点仍然可以提供服务直到主节点回来,有点类似一致性哈希的概念。节点的主从关系和顺序也是通过zookeeper保证。消息顺序的实现是通过称为router的路由到固定节点做传输,router默认是策略不是固定而是RR。TT的数据存储优先放在内存,并设置了一个内存状况监视的组件,当发现内存放不下的时候,swap到磁盘文件缓存,实现类似内存换页的功能。正常情况数据都应该在内存,当然如果可靠级别要求高的话可以先存磁盘再传输。TT目前仍然还是比较适合传输日志这样的文本增量数据,并且提供了TailFile这样的python脚本帮你做这个事情,这个脚本可以通过checkpoint做断点续传。在学习这个项目的时候,发现文档有很大问题,要么错误,要么遗漏,并且代码也不是最新的,我估计开源出来外面的人用的还不太多,希望慢慢能搞的更好一些。
跟TT类似,另一个追求高吞吐量的MQ是linkedin开源的
kafka。Kafka就跟这个名字一样,设计非常独特。首先,kafka的开发者们认为不需要在内存里缓存什么数据,操作系统的文件缓存已经足够完善和强大,只要你不搞随机写,顺序读写的性能是非常高效的。kafka的数据只会顺序append,数据的删除策略是累积到一定程度或者超过一定时间再删除。Kafka另一个独特的地方是将消费者信息保存在客户端而不是MQ服务器,这样服务器就不用记录消息的投递过程,每个客户端都自己知道自己下一次应该从什么地方什么位置读取消息,消息的投递过程也是采用客户端主动pull的模型,这样大大减轻了服务器的负担。Kafka还强调减少数据的序列化和拷贝开销,它会将一些消息组织成Message Set做批量存储和发送,并且客户端在pull数据的时候,尽量以zero-copy的方式传输,利用sendfile(对应java里的FileChannel.transferTo/transferFrom)这样的高级IO函数来减少拷贝开销。可见,kafka是一个精心设计,特定于某些应用的MQ系统,这种偏向特定领域的MQ系统我估计会越来越多,垂直化的产品策略值的考虑。
在此期间,我还重新去看了activemq和hornetq的存储实现,从实现上大家都大同小异,append log + data file的模式。Activemq采用异步队列写来提高吞吐量,而Hornetq干脆就直接利用JNI调用原生aio来实现高性能。在搜索Java的aio实现的时候,碰巧发现Mina的沙箱里有个aioj的实现,源码在:
https://svn.apache.org/repos/asf/mina/sandbox/mheath/aioj/ 。我测试了完全可用,也尝试改造我们的磁盘存储组件,可惜提升不多,估计不从整个设计上调整服务器,不大可能从aio上获益。
最近也重新看起了clojure的一些开源项目,clojure的开源资源在github上也非常丰富,有待挖掘,下次有机会再尝试介绍一二。