kafka基础总结

57 阅读10分钟

什么是kafka?

Kafka是由Linkedin公司开发的,它是一个分布式的,支持多分区、多副本,基于Zookeeper的分布式消息流平台,它同时也是一款开源的基于发布订阅模式的消息引擎系统。

kafka的基本术语

  • 消息:Kafka中的数据单元被称为消息,也被称为记录,可以把它看作数据库表中某一行的记录。
  • 批次:为了提高效率,消息会分批次写入Kafka,批次就代指的是一组消息。
  • 主题:消息的种类称为主题(Topic),可以说一个topic代表了一类消息。相当于是对消息进行了分类,主题就类似于数据库中的表。
  • 分区:主题可以被分为若干个分区(partition),同一个主题中的分区可以不在一个机器上,有可能会部署在多个机器上,由此来实现kafka的伸缩性。topic中的单一分区有序,但是无法保证topic中的所有分区有序。

01.png

  • 生产者:向主题发布消息的客户端应用程序称为生产者(Producer)。生产者用于持续不断的向某个主题发送消息。
  • 消费者:订阅主题消息的客户端程序称为消费者(Consumer),消费者用于处理生产者产生的消息。
  • 消费者群组:一个生产者可以对应多个消费者,消费者群组(Consumer Group)指的就是由一个或多个消费者组成的群体。

消费者群组读取消息.jpeg

  • 偏移量:偏移量(Consumer Offset)是一种元数据,它是一个不断递增的整数值,用来记录消费者发送重平衡时的位置,以便用来恢复数据。
  • broker:一个独立的Kafka服务器就被称为broker,broker接收来自生产者的消息,为消息设置偏移,并提交消息到磁盘保存。
  • cluster:broker集群由一个或多个broker组成,每个集群都有一个broker同时充当了集群控制器的角色(Cluster Controller)。在集群内,一个分区由一个broker负责,这个broker也称为这个分区的Leader;当然一个分区可以复制到多个broker上来实现冗余,这样当broker故障时可以将其分区重新分配到其他broker来负责。
  • 副本:Kafka中消息的备份又叫做副本(Replica),副本的数量是可以配置的,Kafka定义了两类副本:领导者副本(Leader Replica)和追随者副本(Follower Replica),前者对外提供服务,后者只是被动跟随。
  • 重平衡:Rebalance,消费者组内某个消费者实例挂掉后,其他消费者实例自动重新分配订阅主题分区的过程。Rebalance是Kafka消费者实现高可用的重要手段。

kafka的核心API

Kafka有四个核心API,它们分别是:

apis.jpeg

  • Producer API,它允许应用程序向一个或多个topics上发送消息记录。
  • Consumer API,允许应用程序订阅一个或多个topics并处理为其生成的记录流。
  • Streams API,允许应用程序作为流处理器,从一个或多个topics中消费输入流,有效的将输入流转换为输出流
  • Connector API,允许构建和运行将Kafka topic连接到现有应用程序或数据系统的可用生产者和消费者。例如:关系数据库的连接器可能会捕获对表的所有更改。

生产者写消息的基本流程

producer.jpeg

  1. 首先,我们需要创建一个ProducerRecord,这个对象需要包含消息的主题(topic)和值(value),可以选择指定一个键值(key)或者分区(partition)
  2. 发送消息时,生产者会对键值和值序列化成字节数组,然后发送到分配器(partitioner)
  3. 如果我们指定了分区,生产者就知道了消息所属的topic和partition。如果没有指定分区,则使用key的hash函数映射一个分区,如果发送的过程中既没有分区也没有key,则将以循环的方式分配一个分区。ProducerRecord还有关联的时间戳。如果没有用户没有提供时间戳,那么生产者将会在记录中使用当前的时间作为时间戳。Kafka最终使用的时间戳取决于topic的配置:
  • 如果主题配置为使用CreateTime,则生产者记录中的时间戳将由broker使用。
  • 如果主题配置为使用LogAppendTime,则生产者记录中的时间戳将在消息添加到其日志中时,由broker重写。
  1. 然后这条消息被存放在一个记录批次上,这个批次里的所有消息都会被发送到相同的主题和分区上。由一个独立的线程负责把它们发到Kafka Broker上。
  2. 当broker接收到消息后,如果成功写入则返回一个包含消息的topic、partition及offset的RecordMetadata对象,否则返回异常
  3. 生产者接收到结果后,对于异常可能会重试

消费者、消费组及消费者重平衡

KafkaConsumer

消费者使用KafkaConsumer从Kafka订阅主题并接收来自这些主题的消息,然后再把它们保存起来。如果只使用单个消费者的话,一段时间后,当生产者写入的速度超过消费者消费的速度,就会导致消息堆积。这个时候就需要多个消费者共同参与消费消息,并对消息进行分流。 Kafka消费者属于消费者群组。一个群组中的消费者订阅的都是相同的主题,每个消费者可以接受主题中一部分分区的消息。

1个消费者消费四个分区.jpeg

2个消费者消费4个分区.jpeg

四个消费者消费四个分区.jpeg

五个消费者消费四个分区.jpeg

从上图可以看出,我们可以通过增加消费组的消费者来提升消费能力。这也是为什么建议创建主题时使用比较多的分区数。但消费者数量不应该比分区多,因为多出来的消费者是空闲的,并没有任何帮助。

Kafka一个重要的特性是,只需写入一次消息。可以支持任意多的应用读取这个消息。即每个应用都可以读取到全量的消息。那为了每个应用都能读取到全量的消息,每个应用都应该有自己的消费组。

两个消费组消费一个主题.jpeg

在这个场景中,消费组 G1 和消费组 G2 都能收到 T1 主题的全量消息,在逻辑意义上来说它们属于不同的应用。

总结起来就是如果应用需要读取全量消息,那么请为该应用设置一个消费组;如果该应用消费能力不足,那么可以考虑在这个消费组里增加消费者。

消费者组

消费者组(Consumer Group)是由一个或多个消费者实例(Consumer Instance)组成的群组,具有可扩展性和可容错性的一个机制。消费者组内的消费者共享一个消费者ID,这个ID叫作Group ID,组内的消费者共同对一个主题进行订阅和消费,同一个组内的消费者只能消费一个分区的消息。 两种消费方式:

  • 一个消费者群组消费一个主题中的消息,这种消费模式又称为点对点的消费方式,点对点的消费方式又被成为消息队列。
  • 一个主题中的消息被多个消费者共同消费,这种消费模式又称为发布-订阅模式。

消费者重平衡

我们从上面的消费者演变图中可以知道这么一个过程:最初是一个消费者订阅一个主题并消费其全部分区的消息,后来有一个消费者加入群组,随后又有更多的消费者加入群组,而新加入的消费者实例分摊了最初消费者的部分消息,这种把分区的所有权通过一个消费者转到其他消费者的行为称为重平衡,英文名也叫做 Rebalance 。 重平衡非常重要,它为消费者群组带来了高可用性 和 伸缩性,我们可以放心的添加消费者或移除消费者,不过在正常情况下我们并不希望发生这样的行为。在重平衡期间,消费者无法读取消息,造成整个消费者组在重平衡的期间都不可用。另外,当分区被重新分配给另一个消费者时,消息当前的读取状态会丢失,它有可能还需要去刷新缓存,在它重新恢复状态之前会拖慢应用程序。

重平衡.jpeg

消费者通过向组织协调者(Kafka Broker)发送心跳来维护自己是消费者组的一员并确认其拥有的分区。对于不同不的消费群体来说,其组织协调者可以是不同的。只要消费者定期发送心跳,就会认为消费者是存活的并处理其分区中的消息。当消费者检索记录或者提交它所消费的记录时就会发送心跳。

如果过了一段时间 Kafka 停止发送心跳了,会话(Session)就会过期,组织协调者就会认为这个 Consumer 已经死亡,就会触发一次重平衡。如果消费者宕机并且停止发送消息,组织协调者会等待几秒钟,确认它死亡了才会触发重平衡。在这段时间里,死亡的消费者将不处理任何消息。在清理消费者时,消费者将通知协调者它要离开群组,组织协调者会触发一次重平衡,尽量降低处理停顿。

Partition和消费模型

上面我们说过,Kafka只能保证在partition内消息是有序的,无法保证全局的消息顺序。 那partition可以被不同的Consumer Group多次消费,那partition被消费的消息是何时删除呢?partition又是如何知道一个Consumer Group当前消费的位置呢?

无论消息是否被消费,除非消息到期partition从不删除消息。假设设置保留时间为2天,则消息发布2天内任何Group都可以消费,2天后消息自动被删除。另partition会为每一个Consumer Group保存一个偏移量,记录Group消费到的位置。

为什么kafka是pull模型

消费者从broker要数据(pull);broker向消费者推送数据(push)。

Kafka选择的是由生产者从broker push消息并由消费者从broker pull消息。因为push模式消息发送速率是broker决定的,所以很难适应消费速率不同的消费者。push模式的目标是尽可能以最快的速度传递消息,但这样很容易造成Consumer来不及处理消息。而pull模式可以根据Consumer的消费能力以适当的速率消费,Consumer也可自己控制消费方式-批量消费or逐条消费,同时还能选择不同的提交方式来实现不同的传输语义。

kafka如何保证可靠性

Kafka 中的可靠性保证有如下四点:

  • 对于一个分区来说,它的消息是有序的。如果一个生产者向一个分区先写入消息A,然后写入消息B,那么消费者会先读取消息A再读取消息B。
  • 当消息写入所有in-sync状态的副本后,消息才会认为已提交(committed)。这里的写入有可能只是写入到文件系统的缓存,不一定刷新到磁盘。生产者可以等待不同时机的确认,比如等待分区主副本写入即返回,后者等待所有in-sync状态副本写入才返回。
  • 一旦消息已提交,那么只要有一个副本存活,数据不会丢失。
  • 消费者只能读取到已提交的消息。