前言

Kafka体系中有很多概念和术语,比如主题(Topic)、分区(Patition)等,提前熟练掌握这些概念对后续深入学习Kafka各种功能和特性将大有裨益。下面我们一起来认识一下这些概念吧~

服务节点Broker

对于Kafka而言,broker可以简单地看作一个独立的Kafka服务节点或Kafka服务实例,一般由多个broker组成一个Kafka集群。这些brokers也可以称为Kafka的服务端,负责接收和处理客户端发送过来的请求,以及对消息进行持久化。

Kafka集群中虽然多个brokers也能运行在同一台物理机器上,但生产线上更常见的做法是将不同的broker分散运行在不同的物理机上。这样即使Kafka集群中某一台机器宕机了,那其他broker也依旧能对外提供服务。这也是Kafka实现高可用的手段之一。

broker重要的配置参数:

  1. broker.id。该参数用来指定Kafka集群中broker的唯一标识,默认值为-1。如果没有设置,那么Kafka会自动生成一个。但是为了避免zookeeper生成的id和用户自行配置的id冲突,自动生成的broker.id是从reserved.broker.max.id 加1。
  2. log.dirs。Kafka把所有消息都保存在磁盘上,而这个参数用来配置日志文件存放的根目录,默认路径为/tmp/kafka-logs。
  3. zookeeper.connect。该参数指明broker要连接的Zookeeper集群的服务地址(格式为host:port),没有默认值。如果Zookeeper集群有多个节点,则可以用逗号将每个节点隔开(格式为host1:port,host2:port)。

生产者Producer

向Kafka发布(Publish)主题消息(Record)的客户端应用程序称为生产者(Producer)。在Kafka,producer和consumer彼此是完全解耦和独立的,这是实现Kafka众所周知的高可伸缩性的关键设计元素点。producer无需关心或者等待consumer的状态,通常只需持续不断地向一个或多个主题发布消息。

producer重要的配置参数:

  1. bootstrap.servers。该参数用来指定生产者客户端连接Kafka集群所需的brokers地址列表,格式为host1:port,host2:port,host3:port,可以设置一个或多个地址,中间以逗号隔开,此参数的默认值为空。并非需要设置所有的broker地址,不过建议至少设置两个以上的broker地址,当其中一个宕机时,producer依然可以连接到Kafka集群上。
  2. key.serializer和value.serializer。这两个参数分别用来指定key和value序列号操作的序列化器,这两个参数默认值为空。注意这里必须填写序列化器的全限定名,如org.apache.kafka.common.serialization.StringSerializer,单单指定StringSerializer是错误的。

消费者Consumer

向Kafka订阅(subscription)主题消息的客户端应用程序称为消费者(Consumer)。consumer负责订阅Kafka集群上一个或多个主题,并且从订阅的主题上拉取消息,进而做相应的业务逻辑处理。

Kafka的消费模式上还有一层消费组(Consumer Group)的概念。所谓消费组,指的是多个消费者实例共同组成的一个组,由它来消费其订阅的topic。每个消费者都有一个对应的消费组,当消息发布到topic之后,只会由组内的一个消费者实例消费,其他消费者实例不能消费它。这就是为什么Kafka要引入消费组的原因,可以提升消费端的吞吐量。

消费组是一个逻辑上的概念。每一个消费组都会有一个固定的名称,消费者在进行消费前需要指定其所属的消费组的名称,这个可以通过在消费者客户端参数group.id来配置,该参数默认值为空。

consumer重要的配置参数:

  1. bootstrap.servers。该参数用来指定消费者客户端连接Kafka集群所需的brokers地址列表,格式为host1:port,host2:port,host3:port,可以设置一个或多个地址,中间以逗号隔开,此参数的默认值为空。并非需要设置所有的broker地址,不过建议至少设置两个以上的broker地址,当其中一个宕机时,producer依然可以连接到Kafka集群上。
  2. group.id。消费者隶属的消费组的名称,是一个标识唯一性的字符串,默认值为空。一般而言,这个参数建议设置成具有一定的业务意义名称。
  3. key.serializer和value.serializer。这两个参数分别用来指定key和value序列号操作的序列化器,这两个参数默认值为空。注意这里必须填写序列化器的全限定名,如org.apache.kafka.common.serialization.StringSerializer,单单指定StringSerializer是错误的。

主题Topic和分区Partition

主题和分区是Kafka的两个核心概念。前面讲到的producer和consumer所针对的实际上是主题和分区层面的操作。主题和分区都是一种逻辑概念,用来区分业务数据的划分,真正在物理层存储的是日志(Log)文件。发送的消息被追加到指定分区日志文件中,并且同时会分配一个特定的偏移量(Offset)。Offset是消息在分区中的唯一标识,它不能跨越其所在分区,所以Kafka通过它来保证消息在分区内的有序性。*注意,Kafka保证的是分区有序而不保证主题有序*

如上图,一个主题Topic1的四个分区可以分布在不同的broker节点上。每一条消息从生产者端发送到broker之前,会根据分区规则选择存储到哪个具体的分区。如果分区规则设定得合理,所有消息都可以均匀地分配到不同的分区中。分区的划分不仅为Kafka提供了可伸缩性、水平扩展的功能,还通过多副本机制来为Kafka提供数据冗余以提高数据可靠性。

区分多副本(Replica)机制是什么?其实就是Kafka为了提升容灾能力做出的数据冗余存储机制,同一条消息能够被拷贝到多个地方保存,这些地方的文件就是所谓的副本。副本分为领导者副本(Leader Replica)和追随者副本(Follower Replica)。Leader副本负责处理读写请求,Follower副本只负责与Leader副本的消息做同步。

如上图,集群中存在4个broker,有个主题拥有3个分区,每个分区有用1个Leader副本和2个Follower副本。producer/consumer客户端只与Leader副本进行交互,而Follower副本只负责与Leader副本进行消息同步(Follower副本大部分时间对Leader副本而言是有会一定的消息滞后的)。

点对点P2P和发布订阅Pub/Sub

对于消息中间件而言,传统的消息系统有两个模块:点对点模式和发布/订阅模式。点对点模式是基于队列的,消息生产者发送消息到队列,一组消费者可以从服务器读取消息,每个消息都会被其中一个消费者处理。在发布/订阅模式里,发送到主题中的消息被广播到所有的消费者。

但传统的这两种模式都具有一定的优点和缺点。点对点的优点是它可以让你把数据分配给多个消费者去处理,可以扩展消费者的处理能力;但缺点是其不支持有多个订阅者,一旦一个消费者读取了数据,那么这个数据在队列中就消失了。发布/订阅模式可以让你广播数据到多个消费者,但是却无法进行扩展处理,因为每条消息都会发送给所有的订阅者,所有消费者的处理能力无法平衡扩展。

为解决这个问题,Kafka引入了消费组(Consumer Group)概念。消费组在Kafka有两层概念。在点对点模式中,允许将数据分配给消费组(多个消费者)处理;在发布订阅中,允许将数据广播给多个消费组(其中一个消费者)处理。

总结

总结一下本次提到的所有名词术语: 1.服务节点:Broker 2.消息:Record 3.生产者:Producer 4.消费者:Consumer 5.消费组:Consumer Group 6.消费者位移:Consumer Offset 7.主题:Topic 8.分区:Partition 9.副本:Replica(领导者副本Leader Replica和跟随者副本Follower Replica) 10.日志:Log 11.点对点模式:P2P 12.发布订阅模式:Pub/Sub

最后再用一张图系统地展示上面这些主要概念的关系: