「Kafka 系列(一)」- Kafka 入门

1,159 阅读6分钟

前言

本文主要讲解了Kafka的消费模型,以及学习Kafka必须要懂的基础概念,通过学习和整理,将入门的部分用我认为更容易理解的方式整合到一起,希望对你有所帮助

简介

Kafka 是一个分布式、支持分区的(partition)、多副本的(replica),基于 Zookeeper 协调的分布式消息系统。Kafka 基于 ScalaJava 开发,相比较于其他消息队列,其设计中大量使用了批量处理和异步的思想,最高可以每秒处理千万级别的消息

Kafka 与周边生态系统的兼容性是最好的没有之一,尤其在大数据和流计算领域

Kafka 具有三个关键功能:

  1. 消息队列:发布和订阅消息流,这个功能类似于消息队列,这也是 Kafka 也被归类为消息队列的原因。
  2. 容错的持久方式存储记录消息流: Kafka 会把消息持久化到磁盘,有效避免了消息丢失的风险·。
  3. 流式处理平台: 在消息发布的时候进行处理,Kafka 提供了一个完整的流式处理类库。

Kafka 主要有两大应用场景:

  1. 消息队列 :建立实时流数据管道,以可靠地在系统或应用 程序之间获取数据
  2. 数据处理: 构建实时的流数据处理程序来转换或处理数据流

Kafka 的消费模型

Kafka 采用了 发布 - 订阅模型

发布订阅模型(Pub-Sub) 使用主题(Topic) 作为消息通信载体,类似于广播模式;发布者发布一条消息,该消息通过主题传递给所有的订阅者,在一条消息广播之后才订阅的用户则是收不到该条消息的

顺便解释一下上面出现的几个名词的概念:

Producer(生产者) :消息的生产方

Consumer(消费者) :消息的消费方

Broker(代理) :对于 Broker 可以简单理解为一个独立的 Kafka 实例, 通过分布式架构,Kafka 集群可以横向扩容很多的 Broker,以增加自己的并发处理能力

Topic(主题)Producer 将消息发送到特定的主题,Consumer 通过订阅特定的 Topic(主题) 来消费消息

Partition(分区)Partition 属于 Topic 的一部分。一个 Topic 可以有多个 Partition ,并且同一 Topic 下的 Partition 可以分布在不同的 Broker 上,这也就表明一个 Topic 可以横跨多个 Broker,但是 Partition 不会跨越 Broker

GroupId(消费组 ID) :每个消费者都会有一个 GroupIdGroupId 相等的话代表他们属于同一个消费组

Offset(消息在 Partition 的偏移量) :消息被追加到 Partition 时都会被分配一个 OffsetPartition 会维护每个 GroupIdOffset,也就是记录不同消费组消费的位置,尽管一个消费组有多个消费者,但它们只能按顺序的消费这个 Partition 中的消息,而不会重复消费

从不同角度解释Kafka的消费机制

根据Kafka的消息模型图,从不同的角度来描述一下 Kafka 的消费机制

对于 Topic 来说:

  1. 消费者在给 Topic 发送消息时:
  • 如果在发消息的时候指定了分区,则消息投递到指定的分区
  • 如果既没有指定分区,且消息的 Key 也是空,则用轮询的方式选择一个分区
  • 如果没有指定分区,但是消息的 Key 不为空,则基于 Key 的哈希值来选择一个分区
  1. Topic 可以跨 Broker,但是 Partition 不会
  2. Topic不保证不同Partition消息的顺序,只能保证同一个Partition中的消息是有序的
  3. Topic会给所有的订阅组发送各个Partition中的消息,并且Partition会维护各个消费组的Offset以确保不会重复消费

对于Consumer来说:

  1. 每个Consumer都有一个GroupId(消费组ID),一个消费组可以有多个Consumer
  2. Consumer可以订阅多个Topic,但是对于Topic发送的消息,同一个消费组不会重复的收到Topic的消息。也就是说,哪怕一个消费组的多个Consumer都订阅了某一Topic,但是Topic过来的消息只会给其中一个Consumer,其它订阅该Topic的Consumer不会再重复收到

如何保证消费顺序

保证消费顺序最简单的办法,就是将所有数据指定一个Partition,只管往同一个Partition塞,这样消费者收到的消息是顺序的

另一种办法,是通过发送消息时,指定参数Key和Partition来实现,如果指定了Key,那么相同Key的消息会被发往同一个Partition,这样能保证不同Key的消息是有序的

有一种情况,会导致消息的有序性遭到破坏

假设现在Producer发送消息时,因为网络波动发送失败,进入重试逻辑,此时有另一条本该再它之后的消息被先发到Partition上,然后消息重试成功了,此时重试的消息的顺序就被打乱了

面对严格要求消息有序的情况,只能是把重试次数设为0,然后处理发送失败的情况,如果有其他比较好的方法,欢迎再评论区告诉我

多副本机制(Replica

为了提高消息存储的安全性和Kafka的容灾能力,引入了多副本机制

多副本机制是针对Partition设计的,可以这么理解,Kafka为Partition拷贝了多份,并且这个份数是可以指定的,多份Partition中有一个Leader,其他叫Follower,当Leader不行了,挂了,会从所有Follower中挑一个合格的上位,与Leader同步程度达不到要求的都是不够资格的小弟,不参加Leader选举

我们平时其实只跟Leader打交道,发送的消息都在Leader中,消息提交到Leader后其他Follower会自动从Leader中拉取同步

Zookeeper对Kafka的作用

1. Broker注册

每个 Broker 在启动时,都会到 Zookeeper 上的 /brokers/ids 进行注册,创建属于自己的节点。每个 Broker 就会将自己的 IP 地址和端口等信息记录到该节点中去,如下图:

2. Topic注册

在 Kafka 中,同一个Topic 的消息会被分成多个分区并将其分布在多个 Broker 上,这些分区信息及与 Broker 的对应关系也都是由 Zookeeper 在维护

3. 负载均衡

对于Topic来说,可以指定多个Partition,而多个Partition又可以分不到不同的Broker上

当生产者生产消息后会尽量投递到不同 Broker的Partition中,当Consumer消费的时候,Zookeeper 可以根据当前的 Partition 数量以及 Consumer 数量来实现动态负载均衡

Reference

CSDN:面试官问:kafka中生产者是如何把消息投递到哪个分区的?消费者又是怎么选择分区的?..._程序员小乐-CSDN博客

JavaGuide:Kafka 如何保证消息的消费顺序?