此篇介绍一下Kafka组件中的常用概念和一些基础知识。

Apache Kafka是一个分布式的消息队列/流处理平台,最初由LinkedIn公司采用Scala开发,最初主要用作活动流(Activity Stream)和运营数据处理管道(Pipeline)的基础。
Kafka支持多生产者,多消费者。

Producer

  1. 生产者,即消息发送方。Producer产生的消息将会被发送到某个Topic。
  2. 多个生产者将数据发送到 Kafka 中,Kafka 将它们顺序存储。Kafka 只保证在一个 Partition 内的消息是有序的,而不保证全局有序的情况。
  3. producer在写入数据的时候永远的找leader。

Broker

因为Kafka一般是集群形式的,其中每一个Kafka实例(或者说每台Kafka服务器节点)就是一个Broker,一个Broker上可以放多个Topic。

Topic, Partition 都是抽象的概念。每个 Partition 最终都需要存储在物理机器上,在 Kafka 中一般把这样的物理机器称为 Broker,可以是一台物理机,也可以是一个集群。

物理上,消息是存在 Broker 上的。存储时,每个 Partition 都可以有多个副本。它们会被“均匀”地存储在各个 Broker 中。

Topic

消息是根据Topic进行归类的,Topic的本质是一个目录,即将同一主题消息归类到同一个目录中。一个Topic可以理解为一个消息队列。

Partition

  1. Kafka 在概念上将一个 Topic 分成了多个 Partition,写入 Topic 的消息会被(平均)分配到其中一个 Partition。Partition 中会为消息保存一个 Partition 内唯一的 ID ,一般称为偏移量(Offset)。这样当性能/存储不足时 Kafka 就可以通过增加 Partition 实现横向扩展。
  2. Kafka 是以 Partition 为单位存储消息的,Consumer 在消费时也是按 Partition 进行的。即 Kafka 会保证一个 Consumer 收到的消息中,来自同一个 Partition 的消息是有序的。而来自不同 Partition 的消息则不保证有序。
  3. 对于一个 Partition,它的多个复本存储一般存储在不同 Broker 中,在同一时刻会由 Zookeeper 选出一个主副本来负责所有的读写操作。
  4. Partition在服务器上的具体表现形式就是一个一个的文件夹,每个partition的文件夹下面会有多组segment文件,每组segment文件又包含.index文件、.log文件、.timeindex文件。log文件就是实际存储message的地方,而index和timeindex文件为索引文件,用于检索消息。

Topic是逻辑上的概念,而Partition是物理上的概念。

Segment

Segment 被译为段,将 Partition 进一步细分为若干个 Segment,每个 Segment 文件的大小相等。

消息Message

  1. 消息的结构重点的包含三部分:offset、消息大小、消息体。
  2. 每一条消息记录包含三个要素:键(Key)、值(Value)、时间戳(Timestamp)。

Offset

  1. Partition 中会为消息保存一个 Partition 内唯一的 ID ,一般称为偏移量(Offset)。这样 Consumer 可以根据 Offset 自由决定如何读取消息,例如读取更早的消息,重新消费等。
  2. Kafka 0.9版本之前,comsumer默认将offset保存在Zookeeper中,从0.9版本开始,comsumer默认将offset保存在Kafka一个内置的topic中,该topic为__consumer_offsets。

Consumer

  1. 消费者,即消息接收方。Consumer消费的消息内容来自于某个topic。
一般有两种消费模型,不同模型下消费者的行为是不同的:
1. 队列模式(也叫点对点模式)。多个消费者共同消费一个队列,每条消息只发送给一个消费者。
2. 发布/订阅模式。多个消费者订阅主题,每个消息会发布给所有的消费者。
  1. Consumer采用pull(拉)模式从broker中读取数据。
  2. 在实际的应用中,建议消费者组的consumer数量与partition的数量一致。

Consumer Group

  1. Kafka 引入了 Consumer Group(消费者组)的概念,Consumer Group 是以发布/订阅模式工作的。一个 Consumer Group 中可以有多个 Consumer(消费者),一个 Group 内的消费者以队列模式工作。
  2. 每个 Group 独立消费某个 Topic 的消息,互相不干扰。事实上,Kafka 会为每个 Group 保存一个偏移量,记录消费的位置。每个 Group 可以包含多个 Consumer,它们共同消费这个 Topic。
  3. 每个消费者组都有一个组id。

Zookeeper

Zookeeper集群不属于Kafka内的组件,但Kafka依赖Zookeeper集群保存meta信息。

消息的删除

  1. Partition 中的消息可以被(不同的 Consumer Group)多次消费,那 Partition中被消费的消息是何时删除的? Partition 又是如何知道一个 Consumer Group 当前消费的位置呢?
1. 无论消息是否被消费,除非消息到期 Partition 从不删除消息。例如设置保留时间为 2 天,则消息发布 2 天内任何 Group 都可以消费,2 天后消息自动被删除。
2. Partition 会为每个 Consumer Group 保存一个偏移量,记录 Group 消费到的位置。
  1. 基于时间或基于大小的消息删除策略。
  2. 需要注意的是,Kafka读取特定消息的时间复杂度是O(1),所以删除过期的文件并不会提高Kafka的性能。

Consumer 和 Partition 数量的关系

1. 同一个 Consumer Group 内,一个 Partition 只能被一个 Consumer 消费。
2. 如果 Consumer 的数量大于 Partition 数量,则会有 Consumer 是空闲的。
3. 如果 Consumer 的数量小于 Partition 数量,则一个 Consumer 可能消费多个 Partition。

关于消息分发

消息是Kafka中最基本的数据单元,在Kafka中,一条消息由key、value两部分构成,在发送一条消息时,可以指定这个key,那么producer会根据key和partition机制来判断当前这条消息应该发送并存储到哪个partition中。

Replication

为了实现高可用,Kafka 需要对数据做冗余 (replication)。方案就是存储多份 Partition 在不同的 Broker 上,并为它们的数据进行同步。副本,为保证集群中的某个节点发生故障时,该节点上的partition数据不丢失,且kafka仍然能够继续工作,Kafka提供了副本机制,一个topic的每个分区都有若干个副本,一个leader和若干个follower。

leader

每个分区多个副本的“主”,生产者发送数据的对象,以及消费者消费数据的对象都是leader。

follower

每个分区多个副本的“从”,实时从leader中同步数据,保持和leader数据的同步。leader发生故障时,某个follower会成为新的leader。

Kafka 的各个 Broker 需要与 Zookeeper 进行通信,每个 Partition 的多个副本之间通过 Zookeeper 的 Leader 选举机制选出主副本。所有该 Partition 上的读写都通过这个主副本进行。 其它的冗余副本会从主副本上同步新的消息,就像其它的 Consumer 一样。

分区分配策略

  1. 一个consumer group中有多个consumer,一个topic有多个partition,所以必然会涉及到partition的分配问题,即确定一个partition由哪个consumer来消费。
  2. Kafka有两种分配策略,一是roundrobin,另一种是range。
  3. 默认情况下,Kafka采用的是hash取模的分区算法(range)。
  4. 在订阅了多个topic的情况下,roundrobin策略将会优于range策略。

高可用

Kafka本身提供replica+isr(in-syncreplica set)的机制来保证数据高可用。

核心API

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

重平衡(Rebalance)

  1. 当新的消费者加入消费组,它会消费一个或多个分区,而这些分区之前是由其它消费者负责的。
  2. 当消费者离开消费组(比如重启、宕机等)时,它所消费的分区会分配给其他分区,这种现象称为重平衡(rebalance)。
  3. 重平衡是 Kafka 一个很重要的性质,这个性质保证了高可用和水平扩展。
  4. 需要注意的是,在重平衡期间,所有消费者都不能消费消息,因此会造成整个消费组短暂的不可用。而且,将分区进行重平衡也会导致原来的消费者状态过期,从而导致消费者需要重新更新状态,这段期间也会降低消费性能。

指标

1. 千亿级日志量,PB级数据量。
2. 单个Topic最少可达几十万qps(几十万的写入),集群可达数百万qps。即使是普通的服务器,Kafka也能轻松支持每秒百万级的写入请求,超过了大部分的消息中间件。
3. 据了解,Kafka每秒可以生产约25万消息(50MB),每秒处理55万小(110MB)。
4. 可进行持久化操作。
5. Kafka速度的秘诀在于,它把所有的消息都变成一个批量的文件,并且进行合理的批量压缩,减少网络IO的损耗,通过MMAP提高I/O的速度。写入数据的时候,由于单个Partition(分区)是末尾添加的所以速度最优;读取数据的时候配合sendfile直接暴力输入。