Kafka分布式消息系统
1. 作用
Kafka是一种处理大量数据的新型系统。Kafka基于拉的消费模型让消费者以自己的速度处理消息。如果处理消息时出现了异常,消费者始终可以选择再消费该消息。
Kafka主要的设计约束是吞吐量而不是功能。
队列模型的消息中间件,顺序消息,消息堆积能力,主动拉消息
核心作用:解耦、异步、并行
1.1 特征
严格的消息顺序、丰富的消息拉取模型、高效订阅者水平扩展、实时的消息订阅、亿级的消息堆积能力。
1.1.1 kafka特性
通过O(1)的磁盘数据结构提供消息的持久化,这种结构对于即使数以TB的消息存储也能够保持长时间的稳定性能。
高吞吐量:即使是非常普通的硬件kafka也可以支持每秒数十万的消息。
支持同步和异步复制两种HA
Consumer客户端pull,随机读,利用sendfile系统调用,zero-copy ,批量拉数据
消费状态保存在客户端
消息存储顺序写
数据迁移、扩容对用户透明
支持Hadoop并行数据加载。
支持online和offline的场景。
持久化:通过将数据持久化到硬盘以及replication防止数据丢失。
scale out:无需停机即可扩展机器。
定期删除机制,支持设定partitions的segment file保留时间。
1.1.2 可靠性(一致性)
kafka(MQ)要实现从producer到consumer之间的可靠的消息传送和分发。传统的MQ系统通常都是通过broker和consumer间的确认(ack)机制实现的,并在broker保存消息分发的状态。
即使这样一致性也是很难保证的(参考原文)。kafka的做法是由consumer自己保存状态,也不要任何确认。这样虽然consumer负担更重,但其实更灵活了。
因为不管consumer上任何原因导致需要重新处理消息,都可以再次从broker获得。
1.1.3 kafak系统扩展性
kafka使用zookeeper来实现动态的集群扩展,不需要更改客户端(producer和consumer)的配置。broker会在zookeeper注册并保持相关的元数据(topic,partition信息等)更新。
而客户端会在zookeeper上注册相关的watcher。一旦zookeeper发生变化,客户端能及时感知并作出相应调整。这样就保证了添加或去除broker时,各broker间仍能自动实现负载均衡。
1.1.4 kafka设计目标
高吞吐量是其核心设计之一。
数据磁盘持久化:消息不在内存中cache,直接写入到磁盘,充分利用磁盘的顺序读写性能。
zero-copy:减少IO操作步骤。
支持数据批量发送和拉取。
支持数据压缩。
Topic划分为多个partition,提高并行处理能力。
1.1.5 Producer负载均衡和HA机制
producer根据用户指定的算法,将消息发送到指定的partition。
存在多个partiiton,每个partition有自己的replica,每个replica分布在不同的Broker节点上。
多个partition需要选取出lead partition,lead partition负责读写,并由zookeeper负责fail over。
通过zookeeper管理broker与consumer的动态加入与离开。
1.2 应用场景
日志异步记录:高吞吐量+低一致性要求。
顺序同步:MySQL binlog复制。
消息广播。(消息推送)
分布式消息路由。
1.3 关键概念
Producer :消息生产者,就是向kafka broker发消息的客户端。
Consumer :消息消费者,向kafka broker取消息的客户端
Topic :咋们可以理解为一个队列。
Consumer Group (CG):这是kafka用来实现一个topic消息的广播(发给所有的consumer)和单播(发给任意一个consumer)的手段。一个topic可以有多个CG。topic的消息会复制(不是真的复制,是概念上的)到所有的CG,但每个CG只会把消息发给该CG中的一个consumer。如果需要实现广播,只要每个consumer有一个独立的CG就可以了。要实现单播只要所有的consumer在同一个CG。用CG还可以将consumer进行自由的分组而不需要多次发送消息到不同的topic。
Broker :一台kafka服务器就是一个broker。一个集群由多个broker组成。一个broker可以容纳多个topic。
Partition:为了实现扩展性,一个非常大的topic可以分布到多个broker(即服务器)上,一个topic可以分为多个partition,每个partition是一个有序的队列。partition中的每条消息都会被分配一个有序的id(offset)。kafka只保证按一个partition中的顺序将消息发给consumer,不保证一个topic的整体(多个partition间)的顺序。
Offset:kafka的存储文件都是按照offset.kafka来命名,用offset做名字的好处是方便查找。例如你想找位于2049的位置,只要找到2048.kafka的文件即可。当然the first offset就是00000000000.kafka
2. 分布式架构
2.1 消费组
每个使用者进程都属于一个使用者小组(consumer group) 。
准确地讲,每条消息都只会发送给每个使用者小组中的一个进程。
因此,使用者小组使得许多进程或多台机器在逻辑上作为一个单个的使用者出现。使用者小组这个概念非常强大,可以用来支持JMS中队列(queue)或者话题(topic)这两种语义。
为了支持队列语义,我们可以将所有的使用者组成一个单个的使用者小组,在这种情况下,每条消息都会发送给一个单个的使用者。
为了支持话题语义,可以将每个使用者分到它自己的使用者小组中,随后所有的使用者将接收到每一条消息。
在我们的使用当中,一种更常见的情况是,我们按照逻辑划分出多个使用者小组,每个小组都是有作为一个逻辑整体的多台使用者计算机组成的集群。在大数据的情况下,Kafka有个额外的优点,对于一个话题而言,无论有多少使用者订阅了它,一条条消息都只会存储一次。
2.2 ZooKeeper
服务注册、服务发现、客户端负载均衡、Offset偏移量分布式存储。
Broker和Consumer都在ZooKeeper中注册,ZooKeeper保存它们的元数据。
有Broker和Consumer发生变化时,其他Broker和Consumer都会得到通知。
3.持久化
消息持久化及其缓存
在对消息进行存储和缓存时,Kafka依赖于文件系统。
线性读取和写入是所有使用模式中最具可预计性的一种方式,因而操作系统采用预读(read-ahead)和后写(write-behind)技术对磁盘读写进行探测并优化后效果也不错。预读就是提前将一个比较大的磁盘块中内容读入内存,后写是将一些较小的逻辑写入操作合并起来组成比较大的物理写入操作。
使用文件系统并依赖于页面缓存(Page Cache)要优于自己在内存中维护一个缓存或者什么别的结构。
通过对所有空闲内存自动拥有访问权,我们至少将可用的缓存大小翻了一倍,然后通过保存压缩后的字节结构而非单个对象,缓存可用大小接着可能又翻了一倍。
这还大大简化了代码,因为对缓存和文件系统之间的一致性进行维护的所有逻辑现在都是在OS中实现的,这事OS做起来要比我们在进程中做那种一次性的缓存更加高效,准确性也更高。如果你使用磁盘的方式更倾向于线性读取操作,那么随着每次磁盘读取操作,预读就能非常高效使用随后准能用得着的数据填充缓存。
数据被传输到OS内核的页面缓存中了,OS随后会将这些数据刷新到磁盘的。此外我们添加了一条基于配置的刷新策略,允许用户对把数据刷新到物理磁盘的频率进行控制(每当接收到N条消息或者每过M秒),从而可以为系统硬件崩溃时“处于危险之中”的数据在量上加个上限。
与BTree方式对比
持久化队列可以按照通常的日志解决方案的样子构建,只是简单的文件读取和简单地向文件中添加内容。虽然这种结果必然无法支持BTree实现中的丰富语义,但有个优势之处在于其所有的操作的复杂度都是O(1),读取操作并不需要阻止写入操作,而且反之亦然。这样做显然有性能优势,因为性能完全同数据大小之间脱离了关系 —— 一个服务器现在就能利用大量的廉价、低转速、容量超过1TB的SATA驱动器。虽然这些驱动器寻道操作的性能很低,但这些驱动器在大量数据读写的情况下性能还凑和,而只需1/3的价格就能获得3倍的容量。 能够存取到几乎无限大的磁盘空间而无须付出性能代价意味着,我们可以提供一些消息系统中并不常见的功能。例如,在Kafka中,消息在使用完后并没有立即删除,而是会将这些消息保存相当长的一段时间(比方说一周)。
文章资料
apache kafka消息服务:http://blog.csdn.net/lizhitao/article/details/23743821

浙公网安备 33010602011771号