分布式系统很重要的一个设计原则是松耦合,即尽可能减小子系统间的依赖。这样各个子系统能够相互独立的进行演进,维护,重用等。Message Queue (MQ)是一种很好的解耦手段。要了解MQ在系统整合中的做用,能够看Enterprise Integration Patterns (EIP)这本书或对应的网站。简单说就是发布者只管把消息发布到MQ中而无论谁会来取,一样消息使用者只管只管从MQ取消息而不论是谁发布的。这样发布者和使用者都不用知道对方的存在。html
MQ产品也有不少,开源的也很多。常见的有activeMQ,openMQ,RabbitMQ等。之前也用过MQ系统,而最近在思考SaaS系统中如何使用MQ。因此在网上看看目前有什么样的MQ系统具备比较好的扩展性,能够支持大规模的数据流的,就发现了kafka。java
kafka是LinkedIn开发并开源的一个分布式MQ系统,如今是Apache的一个孵化项目。在它的主页描述kafka为一个高吞吐量的分布式(能将消息分散到不一样的节点上)MQ。在这片博文中,做者简单提到了开发kafka而不选择已有MQ系统的缘由。两个缘由:性能和扩展性。这里作适当解释。apache
基本上目前绝大多数(若是不是全部的)MQ系统都是针对企业集成应用设计的,而不是针对大规模Service应用设计的。二者有什么区别?服务器
企业集成的基本特色是把企业中现存的本不相干的各类应用进行集成。例如:一个企业可能想把财务系统和仓管系统进行集成,减小部门间结算和流通的成本和时间,并能更好的支持上层决策。但这两个系统是由不一样的厂家作的,不能修改。另外企业集成是一个持续渐进的过程,需求变化很是频繁。这对MQ系统的要求是要很是灵活,可定制性要求高。因此常见的MQ系统一般均可以经过复炸的xml配置或插件开发进行定制以适应不一样企业的业务流程的须要。他们大多数都能经过配置不一样程度的支持EIP中定义一些模式。但设计目标并无很重视扩展性和性能,由于一般企业级应用的数据流和规模都不会很是大。即便有的比较大,使用高配置的服务器或作一个简单几个节点的集群就能够知足了。网络
大规模的service是指面向公众的向facebook,google,linkedin和taobao这样级别或有可能成长到这个级别的应用。相对企业集成来说,这些应用的业务流程相对比较稳定。子系统间集成的业务复杂度也相对较低,由于子系统一般也是通过精心选择和设计的并能作必定的调整。因此对MQ系统的可定制性及定制的复杂性要求并不高。但因为数据量会很是巨大,不是几台Server能知足的,可能须要几十甚至几百台,且对性能要求较高以下降成本,因此MQ系统须要有很好的扩展性。负载均衡
kafka正是一个知足SaaS要求的MQ系统,它经过下降MQ系统的复杂度来提升性能和扩展性。异步
kafka的设计文档详细说明了它的设计思路。这里简单列举并讨论一下。分布式
kafka的工做方式和其余MQ基本相同,只是在一些名词命名上有些不一样。为了更好的讨论,这里对这些名词作简单解释。经过这些解释应该能够大体了解kafka MQ的工做方式。性能
MQ要实现从producer到consumer之间的可靠的消息传送和分发。传统的MQ系统一般都是经过broker和consumer间的确认(ack)机制实现的,并在broker保存消息分发的状态。即便这样一致性也是很难保证的(参考原文)。kafka的作法是由consumer本身保存状态,也不要任何确认。这样虽然consumer负担更重,但其实更灵活了。由于无论consumer上任何缘由致使须要从新处理消息,均可以再次从broker得到。测试
kafka的producer有一种异步发送的操做。这是为提升性能提供的。producer先将消息放在内存中,就返回。这样调用者(应用程序)就不须要等网络传输结束就能够继续了。内存中的消息会在后台批量的发送到broker。因为消息会在内存呆一段时间,这段时间是有消息丢失的风险的。因此使用该操做时须要仔细评估这一点。
另外,在最新的版本中,还实现了broker间的消息复制机制,去除了broker的单点故障(SPOF)。
kafka使用zookeeper来实现动态的集群扩展,不须要更改客户端(producer和consumer)的配置。broker会在zookeeper注册并保持相关的元数据(topic,partition信息等)更新。而客户端会在zookeeper上注册相关的watcher。一旦zookeeper发生变化,客户端能及时感知并做出相应调整。这样就保证了添加或去除broker时,各broker间仍能自动实现负载均衡。
负载均衡能够分为两个部分:producer发消息的负载均衡和consumer读消息的负载均衡。
producer有一个到当前全部broker的链接池,当一个消息须要发送时,须要决定发到哪一个broker(即partition)。这是由partitioner实现的,partitioner是由应用程序实现的。应用程序能够实现任意的分区机制。要实现均衡的负载均衡同时考虑到消息顺序的问题(只有一个partition/broker上的消息能保证按顺序投递),partitioner的实现并不容易。我的认为这一点还有待改进。
consumer读取消息时,除了考虑当前的broker状况外,还要考虑其余consumer的状况,才能决定从哪一个partition读取消息。具体的机制还不是很清楚,须要作更深刻的研究。
性能是kafka设计重点考虑的因素。使用多种方法来保证稳定的O(1)性能。
kafka使用磁盘文件保存收到的消息。它使用一种相似于WAL(write ahead log)的机制来实现对磁盘的顺序读写,而后再定时的将消息批量写入磁盘。消息的读取基本也是顺序的。这正符合MQ的顺序读取和追加写特性。
另外,kafka经过批量消息传输来减小网络传输,并使用java中的sendfile和0拷贝机制减小从读取文件到发送消息间内存数据拷贝和内核用户态切换的次数。
根据kafka的性能测试报告,它的性能基本达到了O(1)的复杂度。
从以上来看,我的以为kafka比较适合用来作简单的消息传递和分发,能支持大数据量。但若是须要实现复杂的EIP模式,则不像传统MQ那么容易。并且,由于只有partition内的消息才能保证传递顺序,若是消息的顺序很重要,又须要很好的扩展性,使用kafka实现可能会比较困难。因此,kafka应该比较适合处理简单的事件和消息,例如数据(log)收集,大量事实数据的实时分析(kafka可与MapReduce集成)。
但须要注意的是,kafka如今还只是Apache的孵化项目,还不是很成熟,虽然开发活动仍是比较活跃的。