### 什么是Producer、Consumer、Broker、Topic、Partition? Kafka 将生产者发布的消息发送到 **Topic(主题)** 中,需要这些消息的消费者可以订阅这些 **Topic(主题)**,如下图所示: ![Kafka Topic Partition](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-11/KafkaTopicPartitioning.png) 上面这张图也为我们引出了,Kafka 比较重要的几个概念: 1. **Producer(生产者)** : 产生消息的一方。 2. **Consumer(消费者)** : 消费消息的一方。 3. **Broker(代理)** : 可以看作是一个独立的 Kafka 实例。多个 Kafka Broker 组成一个 Kafka Cluster。 同时,你一定也注意到每个 Broker 中又包含了 Topic 以及 Partition 这两个重要的概念: - **Topic(主题)** : Producer 将消息发送到特定的主题,Consumer 通过订阅特定的 Topic(主题) 来消费消息。 - **Partition(分区)** : Partition 属于 Topic 的一部分。一个 Topic 可以有多个 Partition ,并且同一 Topic 下的 Partition 可以分布在不同的 Broker 上,这也就表明一个 Topic 可以横跨多个 Broker 。这正如我上面所画的图一样。 > 划重点:**Kafka 中的 Partition(分区) 实际上可以对应成为消息队列中的队列。这样是不是更好理解一点?** 我们把生产者和消费者统称为**客户端(Clients)**。你可以同时运行多个 生产者和消费者实例,这些实例会不断地向Kafka集群中的多个主题生产和消费消息 有客户端自然也就有服务器端。Kafka的服务器端由被称为**Broker**的服务进程构成,即一个Kafka集群由多个Broker组成,Broker负责接收和处理客户端发送过来的请求,以及对消息进行持久化。 实现高可用的另一 个手段就是备份机制(Replication)。备份的思想很简单,就是把相同的数据拷贝到多台 机器上,而这些相同的数据拷贝在Kafka中被称为副本(Replica)。好吧,其实在整个分布式系统里好像都 叫这个名字。副本的数量是可以配置的,这些副本保存着相同的数据,但却有不同的角色和作用。Kafka定 义了两类副本:领导者副本(Leader Replica)和追随者副本(Follower Replica)。前者对外提供服务,这 里的对外指的是与客户端程序进行交互;而后者只是被动地追随领导者副本而已,不能与外界进行交互。当 然了,你可能知道在很多其他系统中追随者副本是可以对外提供服务的,比如MySQL的从库是可以处理读 操作的,但是在Kafka中追随者副本不会对外提供服务。对了,一个有意思的事情是现在已经不提倡使用 Master-Slave来指代这种主从关系了,毕竟Slave有奴隶的意思,在美国这种严禁种族歧视的国度,这种表 述有点政治不正确了,所以目前大部分的系统都改成Leader-Follower了。 副本的工作机制也很简单:生产者总是向领导者副本写消息;而消费者总是从领导者副本读消息。至于追随 者副本,它只做一件事:向领导者副本发送请求,请求领导者把最新生产的消息发给它,这样它能保持与领 导者的同步。 讲到这里,你可能有这样的疑问:刚才提到的副本如何与这里的分区联系在一起呢?实际上,副本是在分区 这个层级定义的。每个分区下可以配置若干个副本,其中只能有1个领导者副本和N-1个追随者副本。生产 者向分区写入消息,每条消息在分区中的位置信息由一个叫位移(Offset)的数据来表征。分区位移总是从 0开始,假设一个生产者向一个空分区写入了10条消息,那么这10条消息的位移依次是0、 1、2、、9。 ***** 至此我们能够完整地串联起Kafka的三层消息架构: ●**第一层是主题层**,每个主题可以配置M个分区,而每个分区又可以配置N个副本 ●**第二层是分区层**,每个分区的N个副本中只能有一个充当领导者角色,对外提供服务;其他N-1个副本是 追随者副本,只是提供数据冗余之用。 ●**第三层是消息层**,分区中包含若干条消息,每条消息的位移从0开始,依次递增。 ●**最后**,客户端程序只能与分区的领导者副本进行交互。 ***** #### KafkaBroker的持久化 讲完了消息层次,我们来说说KafkaBroker是如何持久化数据的。 总的来说,Kafka使用**消息日志(Log)**来保存数据,一个日志就是磁盘上一个只能**追加写(Append-only)消息**的物理文件。**因为只能追加写入,故避免了缓慢的随机I/O操作,改为性能较好的顺序I/0写操作,这也是实现Kafka高春吐量特性的一个重要手段**。不过如果你不停地向一个日志写入消息,最终也会耗尽所有的磁盘空间,因此Kafka必然要定期地删除消息以回收磁盘。怎么删除呢?简单来说就是通过**日志段LogSegment)机制**。在Kafka底层,一个日志又近一步细分成多个日志段,消息被追加写到当前最新的日志段中,当写满了一个日志段后,Kafka会自动切分出一个新的日志段,并将老的日志段封存起来。Kafka在后台还有定时任务会定期地检查老的日志段是否能够被删除,从而实现回收磁盘空间的目的。 ***** #### 消息模型 我们知道有两种消息模型,即点对点模型(Peer to Peer,P2P)和发布订阅模型。这里面的点对点指的是同一条消息只能被下游的一个消费者消费,其他消费者则不能染指。在Kafka中实现这种P2P模型的方法就是引入了**消费者组(Consumer Group)。所谓的消费者组,指的是多个消费者实例共同组成一个组来消费一组主题。这组主题中的每个分区都只会被组内的一个消费者实例消费,其他消费者实例不能消费它。为什么要引入消费者组呢?主要是为了提升消费者端的吞吐量**。多个消费者实例同时消费,加速整个消费端的吞吐量(TPS)。我会在专栏的后面详细介绍消费者组机制,所以现在你只需要了解消费者组是做什么的即可。另外这里的消费者实例可以是运行消费者应用的进程,也可以是一个线程,它们都称为一个消费者实例(Consumer Instance)。 消费者组里面的所有消费者实例不仅“瓜分”订阅主题的数据,而且更酷的是它们还能彼此协助。假设组内 某个实例挂掉了,Kafka能够自动检测到,然后把这个Failed实例之前负责的分区转移给其他活着的消费 者。这个过程就是Kafka中大名鼎鼎的“**重平衡”(Rebalance)**。