在 Kafka 的世界中有不少概念和术语是须要你提早理解并熟练掌握的,这对于后面你深刻学习 Kafka 各类功能和特性将大有裨益。服务器
下面我来盘点一下 Kafka 的各类术语。架构
Kafka 属于分布式的消息引擎系统 。在 Kafka 中,发布订阅的对象是主题(Topic),你能够为每一个业务、每一个应用甚至是每类数据都建立专属的主题。向主题发布消息的客户端应用程序称为生产者(Producer),生产者程序一般持续不断地向一个或多个主题发送消息,而订阅这些主题消息的客户端应用程序就被称为消费者(Consumer)。分布式
和生产者相似,消费者也可以同时订阅多个主题的消息。咱们把生产者和消费者统称为客户端(Clients)。你能够同时运行多个生产者和消费者实例,这些实例会不断地向 Kafka 集群中的多个主题生产和消费消息。性能
有客户端天然也就有服务器端。Kafka 的服务器端由被称为 Broker 的服务进程构成,即一个 Kafka 集群由多个 Broker 组成,Broker 负责接收和处理客户端发送过来的请求,以及对消息进行持久化。虽然多个 Broker 进程可以运行在同一台机器上,但更常见的作法是将不一样的 Broker 分散运行在不一样的机器上,这样若是集群中某一台机器宕机,即便在它上面运行的全部 Broker 进程都挂掉了,其余机器上的 Broker 也依然可以对外提供服务。这其实就是 Kafka 提供高可用的手段之一。学习
实现高可用的另外一个手段就是备份机制(Replication)。备份的思想很简单,就是把相同的数据拷贝到多台机器上,而这些相同的数据拷贝在 Kafka 中被称为副本(Replica)。好吧,其实在整个分布式系统里好像都叫这个名字。副本的数量是能够配置的,这些副本保存着相同的数据,但却有不一样的角色和做用。spa
Kafka 定义了两类副本:领导者副本(Leader Replica)和追随者副本(Follower Replica)。线程
对了,一个有意思的事情是如今已经不提倡使用 Master-Slave 来指代这种主从关系了,毕竟 Slave 有奴隶的意思,在美国这种严禁种族歧视的国度,这种表述有点政治不正确了,因此目前大部分的系统都改为 Leader-Follower 了。设计
副本的工做机制也很简单:生产者老是向领导者副本写消息;而消费者老是从领导者副本读消息。
至于追随者副本,它只作一件事:向领导者副本发送请求,请求领导者把最新生产的消息发给它,这样它能保持与领导者的同步。3d
虽然有了副本机制能够保证数据的持久化或消息不丢失,但没有解决伸缩性的问题。伸缩性即所谓的 Scalability,是分布式系统中很是重要且必需要谨慎对待的问题。什么是伸缩性呢?咱们拿副原本说,虽然如今有了领导者副本和追随者副本,但假若领导者副本积累了太多的数据以致于单台 Broker 机器都没法容纳了,此时应该怎么办呢?一个很天然的想法就是,可否把数据分割成多份保存在不一样的 Broker 上?若是你就是这么想的,那么恭喜你,Kafka 就是这么设计的。这种机制就是所谓的分区(Partitioning)。日志
若是你了解其余分布式系统,你可能据说过度片、分区域等提法,好比 MongoDB 和 Elasticsearch 中的Sharding、HBase 中的 Region,其实它们都是相同的原理,只是 Partitioning 是最标准的名称。
Kafka 中的分区机制指的是将每一个主题划分红多个分区(Partition),每一个分区是一组有序的消息日志。生产者生产的每条消息只会被发送到一个分区中,也就是说若是向一个双分区的主题发送一条消息,这条消息要么在分区 0 中,要么在分区 1 中。如你所见,Kafka的分区编号是从 0 开始的,若是 Topic 有 100 个分区,那么它们的分区号就是从 0 到99。
讲到这里,你可能有这样的疑问:刚才提到的副本如何与这里的分区联系在一块儿呢?实际上,副本是在分区这个层级定义的。每一个分区下能够配置若干个副本,其中只能有 1 个领导者副本和 N-1 个追随者副本。生产者向分区写入消息,每条消息在分区中的位置信息由一个叫位移(Offset)的数据来表征。
分区位移老是从 0 开始,假设一个生产者向一个空分区写入了 10 条消息,那么这 10 条消息的位移依次是 0、一、二、…、9。
至此咱们可以完整地串联起 Kafka 的三层消息架构:
最后,客户端程序只能与分区的领导者副本进行交互。
讲完了消息层次,咱们来讲说 Kafka Broker 是如何持久化数据的。
总的来讲,Kafka 使用消息日志(Log)来保存数据,一个日志就是磁盘上一个只能追加写(Append-only)消息的物理文件。
由于只能追加写入,故避免了缓慢的随机 I/O 操做,改成性能较好的顺序I/O 写操做,这也是实现 Kafka 高吞吐量特性的一个重要手段。
不过若是你不停地向一个日志写入消息,最终也会耗尽全部的磁盘空间,所以 Kafka 必然要按期地删除消息以回收
磁盘。
怎么删除呢?简单来讲就是经过日志段(Log Segment)机制。在 Kafka 底层,一个日志又近一步细分红多个日志段,消息被追加写到当前最新的日志段中,当写满了一个日志段后,Kafka 会自动切分出一个新的日志段,并将老的日志段封存起来。Kafka 在后台还有定时任务会按期地检查老的日志段是否可以被删除,从而实现回收磁盘空间的目的。
这里再重点说说消费者。以前提到过两种消息模型,即点对点模型(Peerto Peer,P2P)和发布订阅模型。
这里面的点对点指的是同一条消息只能被下游的一个消费者消费,其余消费者则不能染指。在 Kafka 中实现这种 P2P 模型的方法就是引入了消费者组(Consumer Group)。所谓的消费者组,指的是多个消费者实例共同组成一个组来消费一组主题。
这组主题中的每一个分区都只会被组内的一个消费者实例消费,其余消费者实例不能消费它。为何要引入消费者组呢?主要是为了提高消费者端的吞吐量。多个消费者实例同时消费,加速整个消费端的吞吐量(TPS)。
后面详细介绍消费者组机制,因此如今你只须要了解消费者组是作什么的便可。
另外这里的消费者实例能够是运行消费者应用的进程,也能够是一个线程,它们都称为一个消费者实例(Consumer Instance)。消费者组里面的全部消费者实例不只“瓜分”订阅主题的数据,并且更酷的是它们还能彼此协助。假设组内某个实例挂掉了,Kafka 可以自动检测到,而后把这个 Failed 实例以前负责的分区转移给其余活着的消费者。这个过程就是 Kafka 中大名鼎鼎的“重平衡”(Rebalance)。嗯,其实既是大名鼎鼎,也是臭名昭著,由于由重平衡引起的消费者问题比比皆是。事实上,目前不少重平衡的 Bug 社区都无力解决。
每一个消费者在消费消息的过程当中必然须要有个字段记录它当前消费到了分区的哪一个位置上,这个字段就是消费者位移(Consumer Offset)。注意,这和上面所说的位移彻底不是一个概念。上面的“位移”表征的是分区内的消息位置,它是不变的,即一旦消息被成功写入到一个分区上,它的位移值就是固定的了。
而消费者位移则不一样,它多是随时变化的,毕竟它是消费者消费进度的指示器嘛。另外每一个消费者有着本身的消费者位移,所以必定要区分这两类位移的区别。我我的把消息在分区中的位移称为分区位移,而把消费者端的位移称
为消费者位移。
我来总结一下今天提到的全部名词术语:
最后我用一张图来展现上面提到的这些概念,但愿这张图可以帮助你形象化地理解全部这些