- Kafka名词解释
- Broker:Kafka节点,一个Kafka节点就是一个broker,多个broker可以组成一个Kafka集群。
- Topic:一类消息,消息存放的目录即主题,例如page view日志、click日志等都可以以topic的形式存在,Kafka集群能够同时负责多个topic的分发。
- Partition:topic物理上的分组,一个topic可以分为多个partition,每个partition是一个有序的队列
- Producer : 生产message发送到topic
- Consumer : 订阅topic消费message, consumer作为一个线程来消费
- Consumer Group:一个Consumer Group包含多个consumer, 这个是预先在配置文件中配置好的。各个consumer(consumer 线程)可以组成一个组(Consumer group ),partition中的每个message只能被组(Consumer group ) 中的一个consumer(consumer 线程 )消费,如果一个message可以被多个consumer(consumer 线程 ) 消费的话,那么这些consumer必须在不同的组。
- Kafka集群概览
- 剖析一个Topic的生产与消费
- 生产者
集群模式下,ProducerA和ProducerB都是“my topic”的生产者,即2个实例
- 消费者
在集群模式下,ConsumerA、ConsumerB和ConsumerC都是“my topic”的消费者,即3个实例,它们都在一个ConsumerGroup中
- My Topic
一个主题,如:用户点击事件
Partition1、Partition2、Partition3是对My Topic按照特定规则的分解,例如
P1存放: key mod 3 = 0
P2存放: key mod 3 = 1
P3存放: key mod 3 = 2
一个topic,在kafka集群里的物理存储怎样?-----Partition & Replication
- Partition在broker中的分布
举例:在一个含有4个broker节点的集群中,每个主题3个分区,每个分区3个备份
bin/kafka-topics.sh --create --zookeeper 192.168.102.197:2181 --replication-factor 3 --partitions 3 --topic topic1
- 创建过程
Step1:创建一个topic
Step2:将这个topic逻辑分3个区
Step3:将这3个区,分到每个broker上(分区数量可以大于broker数量吗?)
Step4:为每个分区,创建对应数量的副本(副本数量可以大于broker数量吗?)
- 消息分配规则:
P0存放: key mod 3 = 0(只有3个分区,每个消息必须落在其中一个分区)
P1存放: key mod 3 = 1
P2存放: key mod 3 = 2
主题名称 | Key | Payload负载 | 所在分区 | 目标Broker |
MyTopic | 1 | Data1 | Part1 | Broker2 |
MyTopic | 2 | Data2 | Part2 | Broker4 |
MyTopic | 3 | Data3 | Part0 | Broker1 |
MyTopic | 4 | Data4 | Part1 | Broker2 |
MyTopic | 5 | Data5 | Part2 | Broker4 |
MyTopic | 6 | Data6 | Part0 | Broker1 |
MyTopic | 7 | Data7 | Part1 | Broker2 |
MyTopic | 8 | Data8 | Part2 | Broker4 |
- 结论:
同一个Partition可能会有多个Replica,需要保证同一个Partition的多个Replica之间的数据一致性。而这时需要在这些Replication之间选出一个Leader(红色背景),Producer和Consumer只与这个Leader交互,其它Replica作为Follower从Leader中复制数据
- Producer发送消息到Kafka集群的过程分析
选择分区
我们从创建一个ProducerRecord 对象开始, Producer Record 对象需要包含目标主题和要发送的内容。我们还可以指定键或分区。在发送ProducerRecord 对象时,生产者要先把键和值对象序列化成字节数组,这样它们才能够在网络上传输。
接下来,数据被传给分区器。如果之前在ProducerRecord 对象里指定了分区,那么分区器就不会再做任何事情,直接把指定的分区返回。如果没有指定分区,那么分区器会根据ProducerRecord 对象的键来选择一个分区。选好分区以后,生产者就知道该往哪个主题和分区发送这条记录了。紧接着,这条记录被添加到一个记录批次里,这个批次里的所有消息会被发送到相同的主题和分区上。有一个独立的线程负责把这些记录批次发送到相应的broker 上。
接收写入结果
服务器在收到这些消息时会返回一个响应。如果消息成功写入Kafka ,就返回一个RecordMetaData 对象,它包含了主题和分区信息,以及记录在分区里的偏移量。如果写入失败, 则会返回一个错误。生产者在收到错误之后会尝试重新发送消息,几次之后如果还
是失败,就返回错误信息。
同步发送消息---通过调用Future.get()方法阻塞,等待结果返回
异步发送消息---回调函数
生产者如何保证消息写入的高可用?
acks 参数指定了必须要有多少个分区副本收到消息,生产者才会认为消息写入是成功的。这个参数对消息丢失的可能性有重要影响。
如果acks=0 ,生产者在成功写入消息之前不会等待任何来自服务器的响应。
如果acks=1 ,只要集群的首领节点收到消息,生产者就会收到一个来自服务器的成功
响应。
如果acks=all ,只有当所有参与复制的节点全部收到消息时,生产者才会收到一个来自
服务器的成功响应。
- Consumer从Kafka集群消费消息的过程分析
主题分区和消费者群组的多种分配方式
消费者群组和分区再均衡
一个新的悄费者加入群组时,它读取的是原本由其他消费者读取的消息。当一个消费者被关闭或发生崩愤时,它就离开群组,原本由它读取的分区将由群组里的其他消费者来读取。在主题发生变化时, 比如管理员添加了新的分区,会发生分区重分配。当消费者要加入群组时,它会向群组协调器发送一个Join Gro up 请求。第一个加入群组的消费者将成为“群主”。群主从协调器那里获得群组的成员列表(列表中包含了所有最近发送过心跳的消费者,它们被认为是活跃的),并负责给每一个悄费者分配分区。它使用一个实现了P a 「ti.ti.onAssi. gn o 「接口的类来决定哪些分区应该被分配给哪个消费者。Kafka 内置了两种分配策略,在后面的配置参数小节我们将深入讨论。分配完毕之后,群主把分配情况列表发送给群组协调器,协调器再把这些信息发送给所有消费者。每个消费者只能看到自己的分配信息,只有群主知道群组里所有消费者的分配信息。这个过程会在每次再均衡时重复发生。
消费者读取消息
poll () 方能返回一个记录列表。每条记录都包含了记录所属主题的信息、记录所在分
区的信息、记录在分区里的偏移量,以及记录的键值对。我们一般会遍历这个列表,逐
条处理这些记录。
消费者指定偏移量进行消费
我们知道了如何使用poll () 方告从各个分区的最新偏移量处开始处理消息。不过,有时候我们也需要从特定的偏移量处开始读取悄息。如果你想从分区的起始位置开始读取消息,或者直接跳到分区的末尾开始读取消息, 可以使用seekToBeginning(Collection<TopicPartition> tp ) 和seekToEnd (Collection < TopicPartition >
tp ) 这两个方法。
消费者提交分区消息偏移量
消费者往一个叫作_consumer_offset 的特殊主题发送消息,消息里包含每个分区的偏移量。如果消费者一直处于运行状态,那么偏移量就没有什么用处。不过,如果悄费者发生崩愤或者有新的消费者加入群组,就会触发再均衡,完成再均衡之后,每个消费者可能分配到新的分区,而不是之前处理的那个。为了能够继续之前的工作,消费者需要读取每个分区最后一次提交的偏移量,然后从偏移量指定的地方继续处理。
提交方式:
自动提交consumerProps.put("enable.auto.commit", "true")
手动提交consumer.commitSync();或consumer.commitAsync();
提交特定的偏移量:边处理边提交
- 安装kafka
- Kafka常用命令