Kafka分区与消费者的关系

Kafka中的topic由partition组成,每个partition有leader和follower,消息先发送给leader,再由follower备份。分区数量设置需权衡吞吐量与资源开销。分区与消费者之间是一对一关系,一个消费者只能消费一个分区,反之一个分区只能被一个消费者消费。分区策略包括指定、key哈希和轮询。消费者组内,分区分配策略包括range、roundrobin和sticky,其中sticky策略能保持分配稳定并提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分区(partition)

kafka中的topic可以细分为不同的partition,一个topic可以将消息存放在不同的partition中。

leader和follower

每个partition可以设置一个leader和多个follower。kafka的消息没有设置读写分离,每个消息发送时,都是发送至对应的partition的leader-paertion,follower-partition主要是为了备份数据而存在,当leader-partition出现故障时,数据已经完全同步的follower-partition也会切换成leader-partition。

AR和ISR

AR:分区中所有的副本统称为AR。
ISR:所有与leader节点保持同步的副本(包括leader节点)组成的节点,生产者首先将消息发送给leader副本,然后follower从leader中同步消息。
ISR是AR的子集。

数据的存储

在partition中,一个topic中的数据存放在不同的partition中,一个分区的内容会存储成一个log文件,为了防止log过大,引入了日志分段,根据一定规则将log切分为多个logSegment,相当于一个巨型文件被切分成了很多不同的文件。log和logSegment关系如下:


Log在物理上只以文件夹的形式存储,日志文件在磁盘的存储如下:

 

主题的分区数设置

在server.properties配置文件中可以指定一个全局的分区数设置,这是对每个主题下的分区数的默认设置,默认是1。

当然每个主题也可以自己设置分区数量,如果创建主题的时候没有指定分区数量,则会使用server.properties中的设置。

bin/kafka-topics.sh --zookeeper localhost:2181 --create --topic my-topic --partitions 2 --replication-factor 1

在创建主题的时候,可以使用--partitions选项指定主题的分区数量

[root@localhost kafka_2.11-2.0.0]# bin/kafka-topics.sh --describe --zookeeper localhost:2181 --topic abc
Topic:abc       PartitionCount:2        ReplicationFactor:1     Configs:
        Topic: abc      Partition: 0    Leader: 0       Replicas: 0     Isr: 0
        Topic: abc      Partition: 1    Leader: 0       Replicas: 0     Isr: 0

分区多的优点

kafka使用分区将topic的消息打散到多个分区,分别保存在不同的broker上,实现了producer和consumer消息处理的高吞吐量。

Kafka的producer和consumer都可以多线程地并行操作,而每个线程处理的是一个分区的数据。因此分区实际上是调优Kafka并行度的最小单元。对于producer而言,它实际上是用多个线程并发地向不同分区所在的broker发起Socket连接同时给这些分区发送消息;而consumer,同一个消费组内的所有consumer线程都被指定topic的某一个分区进行消费。

所以说,如果一个topic分区越多,理论上整个集群所能达到的吞吐量就越大。

分区不是越多越好

分区是否越多越好呢?显然也不是,因为每个分区都有自己的开销:

一、客户端/服务器端需要使用的内存就越多 

客户端producer有个参数batch.size,默认是16KB。它会为每个分区缓存消息,一旦满了就打包将消息批量发出。

分区越多,consumer端获取数据所需的内存越多。同时consumer线程数要匹配分区数(大部分情况下是最佳的消费吞吐量配置)的话,那么这里面的线程切换的开销本身已经不容小觑了。服务器端的很多组件都在内存中维护了分区级别的缓存,比如controller,FetcherManager等,因此分区数越多,这种缓存的成本就越大。

二、文件句柄的开销 

每个分区在底层文件系统都有属于自己的一个目录。该目录下通常会有两个文件: base_offset.log和base_offse

### Kafka 分区消费机制及其实现方式 Kafka分区消费机制是其高效性能的核心之一。它通过将主题划分为多个分区(Partitions),并允许消费者以 Pull 模式从这些分区中获取消息,从而实现了高吞吐量水平扩展能力。 #### 1. 分区的作用 Kafka 使用分区来分割日志文件,使得每个主题可以分布在不同的 Broker 上运行[^4]。这种设计不仅提高了系统的可用性可靠性,还支持更高的并发度。具体而言: - **负载均衡**:不同分区可以在不同的 Broker 节点上存储处理,避免单节点成为瓶颈。 - **顺序保障**:对于同一分区内的消息,Kafka 可以保证严格的顺序性;而对于跨分区的消息,则不提供全局顺序保障。 #### 2. Partition Consumer Group 关系 在一个消费者组(Consumer Group)中,每个消费者实例通常订阅一组特定的分区消费者的数量不应超过该主题的总分区数,否则多余的消费者将会处于闲置状态[^2]。 当某个消费者加入或离开消费组时,Kafka 会触发 Rebalance 过程,重新分配分区消费者之间的映射关系。 #### 3. Pull 模式的实现细节 Kafka消费者采用 Pull 模型工作,这意味着消费者主动向 Kafka 集群请求数据,而非由服务器推送给客户端[^1]。这种方式具有以下优点: - **灵活控制**:消费者可以根据自身的处理能力需求决定何时拉取新一批消息。 - **背压管理**:防止生产者过快发送消息而导致消费者积压过多未处理的数据。 - **精确重试**:如果某些消息未能成功处理,消费者可以选择重新拉取相同偏移量范围内的记录。 以下是基于 Pull 模式的典型代码示例: ```java Properties props = new Properties(); props.put("bootstrap.servers", "localhost:9092"); props.put("group.id", "my-group"); props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props); consumer.subscribe(Arrays.asList("my-topic")); while (true) { ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100)); for (ConsumerRecord<String, String> record : records) { System.out.printf("Offset = %d, Key = %s, Value = %s%n", record.offset(), record.key(), record.value()); } } ``` 上述程序展示了如何创建一个简单的 Kafka 消费者应用,并持续轮询指定的主题中的最新消息。 #### 4. 数据读写的优化 —— 零拷贝技术 为了进一步提升效率,Kafka 利用了操作系统层面的零拷贝(Zero-Copy)功能来减少内存间的频繁复制操作[^5]。相比传统的 I/O 流程涉及多次上下文切换缓冲区转移,零拷贝能够显著降低 CPU 开销并加快传输速度。 --- ###
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值