问题导读
1.为什么要先讲解一些Kafka的概念? 2.Kafka消费者和消费组的概念是什么?两者有什么关系? 3.Kafka如何实现负载均衡?
应用程序需要利用KafkaConsumer订阅kafka的主题并从中接收消息,以这种方式从Kafka中读取数据。从kafka中读取数据和从其他的消息系统有些不同,Kafka有其独有的一些思想和概念。不理解这些概念就不太容易理解怎么使用kafka消费者API。因此,我们会先解释一些重要的概念,然后通过一些实例来展示消费者APIs在不同场景下的实现和应用。
KafkaConsumer Concepts Kafka消费者概念
Consumers and Consumer Groups 消费者和消费者组 假设你有一个应用程序需要从Kafka 主题中读取消息 ,并运行一些验证,将结果写入另一个数据存储区。在这种场景下,你的应用程序会创建消费者对象,订阅合适的主题开始接收,验证消息,写入结果。这可以很好地工作一段时间,但是如果生产者向主题写消息的速率超过了应用程序可以验证它们的速率,那该怎么办呢?如果仅限制于单个消费者阅读和处理数据,那么应用程序可能会越来越落后,无法跟上传入消息的速度。显然,我们需要从主题中扩大消费。就像多个生产者可以写入相同的主题一样,我们需要允许多个消费者从相同的主题中读取数据,并将数据区分开。
kafka消费者通常是消费组的一部分。当属于同一个消费组的多个消费者订阅了同一个主题后,每个消费者只会收到一个主题不同分区的子集。
假设主题t1有4个分区,我们创建一个新的消费者c1,c1只属于消费组g1并且用它来订阅主题t1。消费者c1会获取到来自t1所有的4个分区的消息。 如果我们新增一个消费者c2到消费组g1,每个消费者只会得到来自两个分区的消息。可能消息是从分区0和2到c1,从分区1和3到c2。 如果g1有4个消费者,则将从单个分区分别读取消息。 如果一个消费者组中新增更多的消费者消费同一个主题,并且消费者数目多于分区数目,则会有一些消费者空闲,甚至无法获取任何消息。 我们增强kafka从单个主题消费能力的主要方法就是向消费组中增加消费者。消费者被用来做一些高延迟的的操作例如写入数据库或者HDFS,或是一些计算耗时的操作是很普遍的。在这种情况下,一个消费者是可能无法跟上数据流入主题的速度的;而增加消费者,通过使每个消费者都拥有一个分区或消息子集达到负载均衡 是我们扩展kakfa的主要方法。允许在负载增加时添加更多的消费者,这是创建具有大量分区的主题的一个很好的理由。请注意,对于一个主题,添加多于分区数目的消费者是没有意义的--有些消费者会空闲。我们会在第十章讲解如何选择主题的分区数目。
除了添加消费者以扩展单个应用程序之外,有多个应用程序需要从同一主题读取数据,这也是非常常见的。事实上,kafka的主要设计目标之一是将数据转换成适用于整个组织中的许多用例的kafka主题。在这种情况下,我们需要每个应用程序获取所有消息,而不仅仅是子集。为了保证应用程序获取到主题中的所有消息,就需要保证应用程序有自己的消息组。与许多传统的消息传递系统不同,Kafka扩展了消费者和消费组数量而不损耗性能。
在上面的例子中,如果我们添加一个新的有单个消费者的消费组g2,该消费者将获得主题t1中的所有消息而与消费组g1无关。g2可以拥有不止一个消费者,在这种情况下,他们每个都会得到一个子集,就像我们在g1中所展示的那样,但g2作为一个整体,不管其他消费组如何,都会得到所有的消息。 总之,您需要为每个应用程序创建一个新的消费组,该应用程序需要来自一个或多个主题的所有消息。若你将消费者添加到现有的消费者组,以扩大从主题读取和处理消息的能力,则每组中的其余的每个消费者只得到消息的一个子集。
Consumer Groups - Partition Rebalance 消费组 --分区 负载均衡 正如我们在前面一节中看到的,同一个消费者组中的消费者共享他们订阅的主题分区的所有权。当我们向消费组中添加一个新的消费者时,它开始从以前被另一个用户消费的分区中获取消息。同样的事情发生在消费者关闭或崩溃时,当它离开了这个组,它所消费的分区将被剩下的一个消费者消费掉。当消费组消费的主题被修改时,分区会被重新分配,例如,管理员添加了新的分区。
分区所有权从一个消费者转移到另一个消费者的事件称为负载均衡。负载均衡很重要,因为是它们提供了具有高可用性和可扩展性(让我们轻松安全地添加和删除消费者)的消费组,但在正常情况下,是并不希望它们发生的。在负载均衡的时候,消费者将不消费信息,所以再平衡实际上对整个消费组来说会产生一个短暂的不可用窗口。此外,当分区从一个消费者转移到另一个消费者失去其当前状态时,如果它正在缓存数据,需要刷新缓存-减缓我们的应用程序,直到消费者重新设置好其状态。在本章中我们将讨论如何安全地处理负载均衡和如何避免不必要的负载均衡。
消费者在一个消费组中保持其成员身份的方式以及它们对分配给它们的分区的所有权是通过将心跳发送给指定为组协调员的kafka代理(注意这个代理对于不同的消费组是不同的)实现的。只要用户定期发送心跳,就认为它是活着的,并且从它的分区处理消息。事实上,轮询消息的行为是导致消费者发送这些心跳的原因。如果消费者长时间停止发送心跳,它的会话将超时,组协调器会认为它已经死亡并触发再均衡。请注意,如果一个消费者崩溃并停止处理消息,组协调器将在不需要心跳的情况下在几秒钟内决定它是否已经死亡并触发负载均衡。在那几秒钟内,宕掉的消费者拥有的分区中的消息将不会被处理。当消费者明确地关闭时,消费者会通知组协调员它将离开,组协调员将立即触发负载均衡,减少处理过程中产生的损耗。在本章的后面,我们将讨论配置选项控制心跳频率和会话超时时间和如何将这些符合你的要求。
How does the process of assigning partitions to brokers work? 分配分区到代理的过程是如何完成的?
当消费者要加入到消费组时,它会向组协调员发送一个JoinGroup请求。加入该组的第一个消费者成为leader。leader从组协调器接收组中所有消费者的列表(这将包括最近发送心跳的所有消费者,因此被认为是活着的),它负责给每个消费者分配分区子集。这是通过实现PartitionAssignor接口来决定哪个分区应由哪个消费者处理的。Kafka有两个内置的分区分配策略,我们将在配置部分中更深入地讨论这些策略。在决定了分区分配后,消费者leader发送非配列表给GroupCoordinator,GroupCoordinator将此信息发送给所有的消费者。每个消费者只看到自己的分配信息——leader是唯一拥有该组中完整的消费者列表和他们的分配信息的客户机进程。每次负载均衡都会重复这个过程。
|