1. 定义
Kafka是一个分布式的基于发布/订阅模式
的消息队列
(Message Queue),主要应用于大数据实时处理领域。
2. 消息队列
2.1 传统消息队列的应用场景
传统使用场景就是异步处理:
使用消息队列的好处:
1)解耦
允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。
2)可恢复性
系统的一部分组件失效时,不会影响到整个系统。消息队列降低了进程间的耦合度,所
以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。
3)缓冲
有助于控制和优化数据流经过系统的速度,解决生产消息和消费消息的处理速度不一致
的情况。
4)灵活性 & 峰值处理能力
在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见。
如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。(也称之为去峰)
5)异步通信
很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户
把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。
2.2 消息队列的两种模式
- 点对点模式(一对一,消息主动拉取数据,消息收到后清楚)
消费生产者生产消息发送到Queue中,然后消费者从Queue中拉取并消费消息。消息被消费后,queue中不在存储该消息,所以消息消费者不能消费已经被消费的消息。Queue支持存在多个消费者,但是对一个消息来说,只能有一个消费者得到这个消息。 - 发布/订阅模式(一对多,消费者消费数据之后不会清理消息)
消息生产者(发布)将消息发布到topic中,同时有多个消息消费者订阅该topic。和点对点方式不同的是,发布的topic的消息将被所有订阅者消费。
发布订阅模式有两种数据消费方式:1. 推方式,生产者主动推送给多个消费者消费消息,2.拉方式,消费者从topic中拉取消息进行消费。而kafka采用的是拉方式。
采用拉方式有一个缺点就是消费者需要和生产者保持长轮询,所以在没有消息生产的时候会产生资源浪费。而推的方式会产生消费者消费更不上生产的速度或者生产者跟不上消费者的速度等问题。
Kafka基础架构
基础概念:
- Producer
主题(消息)生产者,发布消息的对象称之为主题生产者(Kafka topic producer) - Consumer
主题(消息)消费者,订阅消息并处理发布的消息的对象称之为主题消费者 - Consumer Group
消费者组,由多个consumer组成。消费者组内每个消费者负责消费不同分区的数据,一个分区只能有一个组内消费者消费;消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。,在消费者组中还有一个组内分区的策略算法,根据不同的策略,会有不同的分区规则。 - Broker
已发布的消息保存在一组服务器中,称之为Kafka集群。集群中的每一个服务器都是一个代理(Broker)。消费者可以订阅一个或者多个主题(topic),并从Broker拉取数据,从而消费这些已经发布的数据。 - Topic
Kafka将这些消息分门别类,每一类消息称之为主题(Topic) - Partition
为了实现扩展性,一个非常大的topic可以分布到多个broker(即服务器)上,一个topic可以分为多个partition,每个partition都是有序的队列。分区的作用还有:1。topic的负载均衡;2。提高读写的并行度。 - Replica
副本,做容灾处理。为保证集群中的某个节点发生故障时,该节点上的 partition 数据不丢失,且kafka任然可以正常工作,kafka提供副本机制,一个topic的每个分区都有若干个副本,一个leader和若干个follower - leader
每个分区多个副本的"主",生产者发送数据的对象,以及消费者消费数据的对象都是leader - follower
每个分区多个副本的"从",实时从leader中同步数据,保持和leader数据的同步。leader发生故障时,通过推举算法某个follower就会成为新的leader
主题和日志(Topic和Log)
Topic是发布消息的类别名,一个topic可以有0个,一个或者多个消费者订阅该主题的消息。
对于每个Topic,kafka集群都会维护一个分区log,就像下图:
每个分区都是一个顺序的,不可变的消息队列,并且可以持续的添加。分区中的消息都被分为一个序列号,称之为偏移量(offset),在每个分区中此偏移量都是唯一的。Kafka集群保持所有的消息,直到他们过期(无论消息是否被消费)。实际上消费者所持有的仅有的元数据就是这个offset(偏移量),也就是说offset由消费者来控制:正常情况下当消费者消费消息的时候,偏移量也线性的增加。但是实际偏移量由消费者控制,消费者可以将偏移量设置成更早的位置,重复读取消息。一个消费者不会影响其他消费者对此log的处理。
分区。Kafka中采用分区的设计有几个目的。一是可以处理更多的消息,不受单台服务器的限制。Topic拥有多个分区意味着它可以不受限的处理更多的数据。第二,分区可以作为并行处理的单元。
分布式(Distribution)
Log的分布式被分布到集群中的多个服务器上。每个服务器处理它分到的分区。根据配置每个分区还可以复制到其他服务器作为备份容错。每个分区都有一个leader,零或者多个follower。leader处理次分区的所有的读写请求,而follower被动的复制数据。如果leader溶剂,其他的一个follower会被推举为新的leader。一台服务器可能同时是一个分区的leader,另一分区的follower。这样就可以平衡负载,避免所有的请求都只让一台或者某几台服务器处理。
Geo-Replication(异地数据同步技术)
Kafka MirrorMaker为群集提供geo-replication
支持。借助MirrorMaker
,消息可以跨多个数据中心或云区域进行复制。 您可以在active/passive场景中用于备份和恢复; 或者在active/passive方案中将数据置于更接近用户的位置,或数据本地化。
生产者(Producers)
生产者往某个Topic上发布消息。生产者也负责选择发布到Topic上的哪一个分区。最简单的方式从分区列表中轮流选择。也可以根据某种算法依照权重选择分区。开发者负责如何选择分区的算法。
消费者(Consumers)
通常来讲,消息模型可以分为两种, 队列
和发布-订阅式
。 队列的处理方式是 一组消费者从服务器读取消息,一条消息只有其中的一个消费者来处理。在发布-订阅模型中,消息被广播给所有的消费者,接收到消息的消费者都可以处理此消息。Kafka为这两种模型提供了单一的消费者抽象模型: 消费者组 (consumer group)。 消费者用一个消费者组名标记自己。 一个发布在Topic上消息被分发给此消费者组中的一个消费者。 假如所有的消费者都在一个组中,那么这就变成了queue模型。 假如所有的消费者都在不同的组中,那么就完全变成了发布-订阅模型。 更通用的, 我们可以创建一些消费者组作为逻辑上的订阅者。每个组包含数目不等的消费者, 一个组内多个消费者可以用来扩展性能和容错。正如下图所示:
2个kafka集群托管4个分区(P0-P3),2个消费者组,消费组A有2个消费者实例,消费组B有4个。
正像传统的消息系统一样,Kafka保证消息的顺序不变。 传统的队列模型保持消息,并且保证它们的先后顺序不变。但是, 尽管服务器保证了消息的顺序,消息还是异步的发送给各个消费者,消费者收到消息的先后顺序不能保证了。这也意味着并行消费将不能保证消息的先后顺序。传统的消息系统,消息的顺序处理很让人头痛。如果只让一个消费者处理消息,又违背了并行处理的初衷。 在这一点上Kafka做的更好,尽管并没有完全解决上述问题。 Kafka采用了一种分而治之的策略:分区。 因为Topic分区中消息只能由消费者组中的唯一一个消费者处理,所以消息肯定是按照先后顺序进行处理的。但是它也仅仅是保证Topic的一个分区顺序处理,不能保证跨分区的消息先后处理顺序。 所以,如果你想要顺序的处理Topic的所有消息,那就只提供一个分区。
Kafka的保证(Guarantees)
- 生产者发送到一个特定的Topic的分区上,消息将会按照它们发送的顺序依次加入,也就是说,如果一个消息M1和M2使用相同的producer发送,M1先发送,那么M1将比M2的offset低,并且优先的出现在日志中。
- 消费者收到的消息也是此顺序。
- 如果一个Topic配置了复制因子(replication factor)为N, 那么可以允许N-1服务器宕机而不丢失任何已经提交(committed)的消息。
kafka作为一个消息系统
- kafka的流与传统企业消息系统相比的概念如何?
传统的消息有两种模式:队列
和发布订阅
。在队列模式中,消费者池从服务器读取消息(每个消息只被其中一个读取);发布订阅模式:消息广播给所有的消费者。这两种模式都有优缺点,队列的优点是允许多个消费者瓜分处理数据,这样可以扩展处理。但是,队列不像多个订阅者,一旦消息者进程读取后故障了,那么消息就丢了。而发布和订阅允许你广播数据到多个消费者,由于每个订阅者都订阅了消息,所以没办法缩放处理。
kafka中消费者组有两个概念:队列:消费者组(consumer group)允许同名的消费者组成员瓜分处理。发布订阅:允许你广播消息给多个消费者组(不同名)。
kafka的每个topic都具有这两种模式。 - kafka有比传统消息系统更强的顺序保证
传统的消息系统按顺序保存数据,如果多个消费者从队列消费,则服务器按存储的顺序发送消息,但是,尽管服务器按顺序发送,消息异步传递到消费者,因此消息可能乱序到达消费者。这意味着消息存在并行消费的情况,顺序就无法保证。消息系统常常通过仅设1个消费者来解决这个问题,但是这意味着没用到并行处理。
kafka做的更好。通过并行topic的parition —— kafka提供了顺序保证和负载均衡。每个partition仅由同一个消费者组中的一个消费者消费到。并确保消费者是该partition的唯一消费者,并按顺序消费数据。每个topic有多个分区,则需要对多个消费者做负载均衡,但请注意,相同的消费者组中不能有比分区更多的消费者,否则多出的消费者一直处于空等待,不会收到消息。