Kafka 的核心概念详解

拓扑结构如下

Broker:Kafka 节点,一个 Kafka 节点就是一个 broker,多个 broker 可以组成一个 Kafka 集群。

        Broker 也即中间的存储队列的节点实例。我们将消息的发布者(Publisher)暂时称作Producer,将消息的订阅者(Subscriber)表述为 Consumer,将中间的存储阵列称作 Broker(代理)

Topic:一类消息,消息存放的目录即主题,例如 page view 日志、click 日志等都可以以 topic的形式存在,Kafka 集群能够同时负责多个 topic 的分发。

        让我们首先深入了解下 Kafka 的核心概念:提供一串流式的记录--Topic

        Kafka 中发布订阅的对象是 Topic。我们可以为每类数据创建一个 Topic,把向 Topic 发布消息的客户端称作 Producer,从 Topic 订阅消息的客户端称作 Consumer。Producers 和 Consumers可以同时从多个 Topic 读写数据。一个 Kafka 集群由一个或多个 Broker 服务器组成,它负责持久化和备份具体的 Kafka 消息。

        Topic 就是数据主题,是数据记录发布的地方,可以用来区分业务系统。Kafka 中的 Topics 总是多订阅者模式,一个 topic 可以拥有一个或者多个消费者来订阅它的数据。

        对于每一个 topic,Kafka 集群都会维持一个分区日志,如下所示:

        每个分区其实都是有序且顺序不可变的记录集,并且不断地追加到结构化的 commit log 文件。分区中的每一个记录都会分配一个 id 号来表示顺序,我们称之为 offset,offset 用来唯一的标识分区中每一条记录。

        Kafka 集群保留所有发布的记录—无论他们是否已被消费—并通过一个可配置的参数——保留期限来控制。举个例子,如果保留策略设置为 2 天,一条记录发布后两天内,可以随时被消费,两天过后这条记录会被抛弃并释放磁盘空间。Kafka 的性能和数据大小无关,所以长时间存储数据没有什么问题。

        事实上,在每一个消费者中唯一保存的元数据是 offset(偏移量)即消费在 log 中的位置。偏移量由消费者所控制:通常在读取记录后,消费者会以线性的方式增加偏移量,但是实际上,由于这个位置由消费者控制,所以消费者可以采用任何顺序来消费记录。例如,一个消费者可以重置到一个旧的偏移量,从而重新处理过去的数据;也可以跳过最近的记录,从某个特定位置开始消费。这些细节说明 Kafka 消费者是非常廉价的—消费者的增加和减少,对集群或者其他消费者没有多大的影响。比如,你可以使用命令行工具,对一些 topic 内容执行 tail 操作,并不会影响已存在的消费者消费数据。

        日志中的 partition(分区)有以下几个用途。第一,当日志大小超过了单台服务器的限制,允许日志进行扩展。每个单独的分区都必须受限于主机的文件限制,不过一个主题可能有多个分区,因此可以处理无限量的数据。第二,可以作为并行的单元集。

Partition:topic 物理上的分组,一个 topic 可以分为多个 partition,每个 partition 是一个有序的队列

        Topic 相当于传统消息系统 MQ 中的一个队列 queue,producer 端发送的 message 必须指定是发送到哪个 topic,但是不需要指定 topic 下的哪个 partition,因为 kafka 会把收到的 message进行 load balance,均匀的分布在这个 topic 下的不同的 partition 上(hash(message) % [broker数量])。物理存储上,这个 topic 会分成一个或多个 partition,每个 partiton 相当于是一个子queue。在物理结构上,每个 partition 对应一个物理的目录(文件夹),文件夹命名是[topicn_ame]_[partition 序号],一个 topic 可以有无数多的 partition,根据业务需求和数据量来设置。在 kafka 配置文件中可随时更改 num.partitions 参数来配置更改 topic 的 partition 数量,在创建 Topic 时通过参数指定 parittion 数量。Topic 创建之后通过 Kafka 提供的工具也可以修改 partiton 数量。

        分区在逻辑上对应着一个 Log,当生产者将消息写入分区的时候,实际上就是写入到了一个Log 中。Log 是一个逻辑概念,对应的是一个磁盘上的文件夹。Log 由多个 Segment 组成,每一个 Segment 又对应着一个日志文件和一个索引文件。

一般来说:

(1)一个 Topic 的 Partition 数量大于等于 Broker 的数量,可以提高吞吐率。

(2)同一个 Partition 的 Replica 尽量分散到不同的机器,高可用。

        当 add a new partition 的时候,partition 里面的 message 不会重新进行分配,原来的 partition里面的 message 数据不会变,新加的这个 partition 刚开始是空的,随后进入这个 topic 的message 就会重新参与所有 partition 的 load balance

        Partition Replica:每个 partition 可以在其他的 kafka broker 节点上存副本,以便某个 kafka broker 节点宕机不会影响这个 kafka 集群。存 replica 副本的方式是按照 kafka broker 的顺序存。例如有 5 个 kafka broker 节点,某个 topic 有 3 个 partition,每个 partition 存 2 个副本,那么 partition1 存 broker1,broker2,partition2 存 broker2,broker3,partition3 存 broker3,broker4(replica 副本数目不能大于 kafka broker 节点的数目,否则报错。这里的 replica 数其实就是partition 的副本总数,其中包括一个 leader,其他的就是 copy 副本)。这样如果某个 broker宕机,其实整个 kafka 内数据依然是完整的。但是,replica 副本数越高,系统虽然越稳定,但是回来带资源和性能上的下降;replica 副本少的话,也会造成系统丢数据的风险。

        Partition leader 与 follower:partition 也有 leader 和 follower 之分。leader 是主 partition,producer 写 kafka 的时候先写 partition leader,再由 partition leader push 给其他的 partition follower。partition leader 与 follower 的信息受 Zookeeper 控制,一旦 partition leader 所在的broker 节点宕机,zookeeper 会冲其他的 broker 的 partition follower 上选择 follower 变为parition leader。

Topic 分配 partition 和 partition replica 的算法:

(1)将 Broker(size=n)和待分配的 Partition 排序。

(2)将第 i 个 Partition 分配到第(i%n)个 Broker 上。

(3)将第 i 个 Partition 的第 j 个 Replica 分配到第((i + j) % n)个 Broker 上

Segment:partition 物理上由多个 segment 组成,每个 Segment 存着 message 信息

Producer : 生产 message 发送到 topic

        学习 Kafka 一定要理解好 Topic,每个 Topic 被分成多个 partition(区)。每条消息在 partition中的位置称为 offset(偏移量),

类型为 long 型数字。消息即使被消费了,也不会被立即删除,而是根据 broker 里的设置,保存一定时间后再清除

,比如 log 文件设置存储两天,则两天后,

不管消息是否被消费,都清除。

Consumer : 订阅 topic 消费 message,consumer 作为一个线程来消费

每个 Consumer 属于一个 Consumer Group

在 kafka 中:

1、 一个 Partition 的消息只会被 group 中的一个 Consumer 消费

2、 可以认为一个 group 就是一个“订阅者”

3、 一个 Topic 中的每个 Partition 只会被一个“订阅者”中的一个 Consumer 消费

        消费者使用一个消费组名称来进行标识,发布到 topic 中的每条记录被分配给订阅消费组中的一个消费者实例。消费者实例可以分布在多个进程中或者多个机器上。

        如果所有的消费者实例在同一消费组中,消息记录会负载平衡到每一个消费者实例。如果所有的消费者实例在不同的消费组中,每条消息记录会广播到所有的消费者进程。

如图,这个 Kafka 集群有两台 server 的,四个分区(p0-p3)和两个消费者组。

消费组 A 有两个消费者,消费组 B 有四个消费者。

        通常情况下,每个 topic 都会有一些消费组,一个消费组对应一个"逻辑订阅者"。一个消费组由许多消费者实例组成,便于扩展和容错。这就是发布和订阅的概念,只不过订阅者是一组消费者而不是单个的进程。

        在 Kafka 中实现消费的方式是将日志中的分区划分到每一个消费者实例上,以便在任何时间,每个实例都是分区唯一的消费者。维护消费组中的消费关系由 Kafka 协议动态处理。如果新的实例加入组,他们将从组中其他成员处接管一些 Partition 分区;如果一个实例消失,拥有的分区将被分发到剩余的实例。

Kafka 只保证分区内的记录是有序的,而不保证主题中不同分区的顺序。每个 partition 分区按照 key 值排序足以满足大多数应用程序的需求。但如果你需要总记录在所有记录的上面,可使用仅有一个分区的主题来实现,这意味着每个消费者组只有一个消费者进程。

Consumer Group:一个 Consumer Group 包含多个 consumer,这个是预先在配置文件中配置好的

        一个 ConsumerGroup 包含多个 consumer,这个是预先在配置文件中配置好的。各个 consumer(consumer 线程)可以组成一个组(Consumer group),partition 中的每个 message 只能被组(Consumer group)中的一个 consumer(consumer 线程)消费,如果一个 message 可以被多个 consumer(consumer 线程)消费的话,那么这些 consumer 必须在不同的组。Kafka不支持一个 partition 中的 message 由两个或两个以上的 consumer thread 来处理,即便是来自不同的 consumer group 的也不行。它不能像 AMQ 那样可以多个 BET 作为 consumer 去处理 message,这是因为多个 BET 去消费一个 Queue 中的数据的时候,由于要保证不能多个线程拿同一条 message,所以就需要行级别悲观锁(for update),这就导致了 consume 的性能下降,吞吐量不够。而kafka为了保证吞吐量,只允许一个 consumer 线程去访问一个 partition。如果觉得效率不高的时候,可以加 partition 的数量来横向扩展,那么再加新的 consumer thread 去消费。这样没有锁竞争,充分发挥了横向的扩展性,吞吐量极高。这也就形成了分布式消费的概念。当启动一个consumer group 去消费一个 topic 的时候,无论 topic 里面有多个少个 partition,无论我们 consumer group 里面配置了多少个 consumer thread,这个consumer group 下面的所有 consumer thread 一定会消费全部的 partition;即便这个 consumer group 下只有一个 consumer thread,那么这个 consumer thread 也会去消费所有的 partition。因此,最优的设计就是,consumer group 下的 consumer thread 的数量等于 partition 数量,这样效率是最高的。

Consumer Rebalance 的触发条件:

(1)Consumer 增加或删除会触发 Consumer Group 的 Rebalance

(2)Broker 的增加或者减少都会触发 Consumer Rebalance

猜你喜欢

转载自blog.csdn.net/u012580143/article/details/84785800