【消息队列MQ】【Kafka&Jafka】

来源:互联网 发布:java简单项目 编辑:程序博客网 时间:2024/06/06 06:39

Why we built this

         Kafka是一个分布式消息队列系统(MQ),起初是LinkedIn为其实时事件流和队列式连续数据处理做的基础服务。现如今已被广泛地应用于很多公司的数据消息队列处理。

         事件流(Activitystream)就是站点上对各种行为的日常报告,就比如为用户展现了什么,他搜索了什么等等。这些信息一般会被日志系统所处理,然后周期性地收集并进行分析挖掘。业务数据(Operational data)是服务器程序执行过程中的产生的各种服务状态性能等

         目前,事件流和业务数据在站点中的地位越来越重要,是其基础构成的一个重要组成部分。

Use cases for activity stream and operational data

l  向好友广播行为状态资讯;

l  通过收集点击、投票、关注等用户行为为其进行关联计算,比如挖掘你的兴趣爱好;

l  安全:站点需要禁用爬虫,速率限制,屏蔽垃圾邮件等其他保护安全措施;

l  运行监控:站点在运行出错时需要能够实时地监控响应报警;

l  报表和批处理:将数据加载到数据仓库或Hadoop系统,以便进行离线分析以及产生相应的商业报表。

Characteristics of activity stream data

         高通量的事件流极不稳定,可能十倍百倍地变化,这对实时计算过程有很大的挑战。

         传统的日志收集为支持离线计算使其具有大规模和可扩展的特点,就比如报表和批量计算;但对于高性能低延迟的实时计算来说会产生更高的操作复杂性要求。另一个层面来说,实际上现有的消息队列系统基本满足了实时或伪实时系统的功能需求,但是面对大量数据造成数据积累而无法及时消费的情景下,他们的持久化功能做的相当不容乐观。就比如以Hadoop系统数据作为离线消息来源时,他们通常一个小时或一天才周期性地向消息队列注入一次,这很容易产生之前说到的那种情景。而Kafka的目标就是能够成为一个高效的队列平台,无论是处理离线的信息还是在线的信息。

Deployment

         下面给出的是Linkedin的简单拓扑视图:


         可以看出,一个Kafka集群系统可以处理来自不同数据源事件流。为离线和在线用户提供单一的数据通道。在这里,他作为不同事件模块异步处理的中间缓冲层,实现各模块的解藕。同时我们也可以使用Kafka将数据复制为多个副本,来服务于不同的离线消费。

         Kafka集群并没有打算实现跨数据中心,但是他支持混合数据源的拓扑结构。通过数据镜像同步来达到这一目的。这一实现非常简单,通过镜像集群来作为数据源的数据服务者。这也意味着他的动态扩展性。下面的例子是为了支持批量负载的多数据源拓扑结构。


可以看出,两个集群中相应节点并没有一致性保证,他们的规模可能就不同,拥有着不同数量的节点。一个单一的集群可以镜像出任意个簇。更多的使用细节请参照【here】

Major Design Elements

几个主要的设计使其区别与其他消息队列系统:

l  支持持久化;

l  高吞吐,同时权衡情况下也为此牺牲其他方面性能;

l  消费状态保存在客户端,而不是Kafka的服务端;

l  绝对的分布式,可以认为producers,brokers,  consumer都可以分布在不同的机器上

这些特征将在后面具体介绍

Basics

首先是一些基本的属性和概念

 

Messages是通信的基本单元。Message可以被producer发布到一个topic中,这意味着在物理上为它被发送到server的一个broker上。很多的consumer可以订阅同一个topic,然后这个topic上的Message就会分发给所有的订阅此topic的consumer。

 

Kafka的分布式特性:producers,consumers, and brokers可以运行在不同的机器上,并且以此构成一个逻辑上的group。这个对于producers和brokers是显然的,但对于consumers来说则需要一点额外的支持【可参照第二个图】。

         每个consumer会被划分到一个consumers组里。在每个consumers组里由统一的一个进程去给这个组里的每一个consumer分发消息(一个consumer接受了,其他的将不会再接收到)。因此,这个consumers组对于Kafka来说就如一个逻辑上的整体。consumers组的概念是非常有用的,可以在语义上支持queue和topic。

         为支持queue的概念实现,我们可以将consumers放在同一个consumersgroup中,这样,一条message只能独占地被其中一个consumer所消费。

         为支持topic的概念,可以将一个consumer作为一个consumersgroup,这样同一条Message就会被所有的consumers所消费。


Message Persistence and Caching

Don't fear the filesystem!

         Kafka在很大程度上依赖文件系统来实现存储和高速消息缓存。我们普遍认为磁盘是慢的,由此使人们怀疑一个具有持久化功能的系统能否展现足够高的性能。事实上,磁盘的所谓快慢完全取决于我们如何去使用它。一个合适的磁盘结构设计可以足以满足于网络请求。

         问题的关键在于,在过去的十年中磁盘的吐量与其寻道时间关联很大。6块 7200RPM SATA RAID5阵列的写速度差不多是300MB/sec。但是随机读取的速度差不多是50/sec 差不多10000倍的差距。可见线性的读写模式是可预见的最适合。因此,操作系统通过检测和预测进行预读和延迟写。这个问题的进一步讨论在ACM的相关队列论文中有一些介绍。他们发现磁盘顺序访问堪比内存的随机访问。

         现代的操作系统为拟补内存与磁盘效率上的差异,会将主存拿来为磁盘做缓存。几乎所有的现代操作系统都非常乐意做出一点牺牲,在内存空闲的时候恨不得将其全部拿来做磁盘缓存用。所有的磁盘读写将通过这一统一的缓存接口。这一特性一直采纳除非你不直接使用I/O接口。因此,当你操作一份数据时,该数据可能复制到OS的页缓存,也就是说实际上有效的写了两次。

         此外,我们将在JVM之上进行开发,进行过JAVA内存开发的人都知道:

l  对象的存储开销很大,会是实际存储数据的一倍,甚至更糟。

l  JAVA的内存回收机制随着堆的规模增长而略显粗糙并性能下降。

         由于这些原因,使用文件系统和页缓存较好地维护了内存cache和其他的架构。我们需要两倍的可用内存空间以适应全内存的访问需求。就比如,我们需要存储的是一个压缩后的整体架构,而不仅仅是数据对象。为此在一个32GB的内存机器上,我们可能会消耗掉28-30GB的内存空间,这是不用考虑内存回收的。另外,这些缓存可以一直保持着(即被持久化),即使计算机重启,这时需要缓存的重建(10G的cache大约需要10分钟),或者我们直接从头来一遍进行冷启动。

         这大大简化业务逻辑代码,因为这些一致性维护等工作都交给了OS去做。这比一堆数据写入时一锤子买卖要靠谱多了。如果你的磁盘使用有利于线性读取,那么预加载将是一个很好的解决方案。

         这使得设计变得简单:与其我们在内存中维持一坨数据,然后将它刷进文件系统,不如反其道而行。不如直接将其持久化到文件系统。实际上,就是把数据放入OS 的页缓存上,然后让OS flush他到磁盘上。我们只提供一个可配置的flush策略就行了。

         以上的相关论文请参见【here】


0 0
原创粉丝点击