📚 前言:快递小哥的困惑
想象一下,你是一个快递站的站长 👨💼,每天有成千上万的包裹需要分配给不同的快递小哥。你会怎么分?
- 随机扔?❌ 太混乱了!
- 按照地址分?✅ 这样同一个小区的包裹都给同一个快递员,效率高!
- 轮流分?✅ 确保每个快递员工作量均衡!
这就是Kafka的分区策略要解决的问题! 🎊
🤔 什么是Kafka的分区?
基础概念
在Kafka中:
- Topic(主题) = 一个大仓库 🏭
- Partition(分区) = 仓库里的多个货架 📦📦📦
- Message(消息) = 要存放的货物 📨
为什么要分区?🤔
- 并行处理 - 多个消费者可以同时从不同分区读取,就像多个收银员同时服务顾客 💰
- 扩展性 - 单个分区存不下了?加分区!就像超市货架不够加货架 🛒
- 容错性 - 一个分区坏了,其他分区还能用 💪
🎲 生产者的分区策略:消息该去哪儿?
1️⃣ 指定分区(Explicit Partition)
最直接粗暴的方式!
ProducerRecord<String, String> record =
new ProducerRecord<>(
"my-topic", // Topic
2, // 指定分区编号:分区2
"key", // Key
"value" // Value
);
生活比喻:📮 你在快递单上直接写:"送到3号货架"。快递员不用思考,直接送到3号货架!
适用场景:
- 你知道某些消息必须去特定分区
- 测试场景
- 特殊业务需求
2️⃣ 根据Key分区(Key-based Partitioning)
最常用的策略! ⭐⭐⭐⭐⭐
ProducerRecord<String, String> record =
new ProducerRecord<>(
"my-topic",
"user-123", // Key
"订单数据" // Value
);
工作原理:
分区编号 = hash(key) % 分区总数
生活比喻:🏠 按照用户的地址(Key)分配快递员。住在"阳光小区"的所有包裹,永远是同一个快递员配送!
核心特点:
- ✅ 相同Key的消息,一定去同一个分区
- ✅ 保证顺序性(同一个用户的消息顺序不会乱)
- ✅ 负载均衡(不同Key会分散到不同分区)
示例场景:
// 用户123的所有订单消息都会在同一个分区
send("user-123", "创建订单");
send("user-123", "支付订单");
send("user-123", "发货");
// 这三条消息的顺序被保证! 🎯
图示:
Key: "user-A" → hash → 123456 → 123456 % 3 = 0 → Partition 0
Key: "user-B" → hash → 789012 → 789012 % 3 = 1 → Partition 1
Key: "user-C" → hash → 345678 → 345678 % 3 = 2 → Partition 2
Key: "user-A" → hash → 123456 → 123456 % 3 = 0 → Partition 0 (又是分区0!)
3️⃣ 轮询分区(Round-Robin)
没有Key时的默认策略!
ProducerRecord<String, String> record =
new ProducerRecord<>(
"my-topic",
null, // Key为null
"消息内容"
);
工作原理:
第1条消息 → Partition 0
第2条消息 → Partition 1
第3条消息 → Partition 2
第4条消息 → Partition 0 (又回到0,循环!)
生活比喻:🎰 像发扑克牌一样,一人一张,轮流发!确保每个人手里的牌数量差不多。
特点:
- ✅ 负载均衡,每个分区消息数量大致相等
- ❌ 无法保证顺序性
- ⚡ 吞吐量较高
4️⃣ 自定义分区器(Custom Partitioner)
终极大招:我的规则我做主! 🎨
public class VIPPartitioner implements Partitioner {
@Override
public int partition(String topic, Object key, byte[] keyBytes,
Object value, byte[] valueBytes, Cluster cluster) {
String keyStr = (String) key;
int numPartitions = cluster.partitionCountForTopic(topic);
// VIP用户走专属分区!
if (keyStr.startsWith("VIP-")) {
return 0; // 分区0专门给VIP
}
// 普通用户走其他分区
return (Math.abs(keyStr.hashCode()) % (numPartitions - 1)) + 1;
}
}
生活比喻:🎭 银行的VIP客户有专属窗口,普通客户在其他窗口排队!
🎯 分区策略对比表
| 策略 | Key | 顺序性 | 负载均衡 | 使用场景 |
|---|---|---|---|---|
| 指定分区 | 不需要 | ❌ | ❌ | 测试、特殊需求 |
| Key分区 | 必须 | ✅(同Key) | ✅ | 最常用,需要顺序性 |
| 轮询 | null | ❌ | ✅ | 无顺序要求,追求吞吐 |
| 自定义 | 可选 | 自定义 | 自定义 | 特殊业务逻辑 |
👥 消费者组的负载均衡:谁来消费哪个分区?
什么是消费者组?
消费者组(Consumer Group) = 一个团队 🤝
- 团队里的每个成员(Consumer)负责处理一部分分区
- 同一条消息,只会被团队里的一个成员处理
- 不同团队可以重复消费相同的消息
图示:
Topic: orders (3个分区)
├─ Partition 0 📦
├─ Partition 1 📦
└─ Partition 2 📦
Consumer Group A: 订单处理团队
├─ Consumer A1 → Partition 0 ✅
├─ Consumer A2 → Partition 1 ✅
└─ Consumer A3 → Partition 2 ✅
Consumer Group B: 数据分析团队
├─ Consumer B1 → Partition 0, 1 ✅
└─ Consumer B2 → Partition 2 ✅
🎪 消费者分区分配策略
1️⃣ Range分配策略(RangeAssignor)
按范围分配,简单粗暴!
工作原理:
- 把分区按顺序排列
- 把消费者按字母顺序排列
- 分区数 ÷ 消费者数 = 每人几个
- 余数分给前面的消费者
示例:
Topic: orders,有7个分区 (P0-P6)
Consumer Group: 3个消费者 (C1, C2, C3)
7 ÷ 3 = 2 余 1
分配结果:
C1: [P0, P1, P2] ← 多分配1个(因为余数是1)
C2: [P3, P4]
C3: [P5, P6]
生活比喻:🍰 切蛋糕,尽量平均分,分不匀的话,老大多吃一块!
优点:
- ✅ 简单易懂
- ✅ 实现简单
缺点:
- ❌ 不够均衡! 第一个消费者可能分到更多分区
- ❌ 多个Topic时,不均衡问题会放大
多Topic场景问题:
Topic1: 3个分区 Topic2: 3个分区
C1: T1[P0], T2[P0] = 2个分区
C2: T1[P1], T2[P1] = 2个分区
C3: T1[P2], T2[P2] = 2个分区
看起来均衡?但如果是:
Topic1: 4个分区 Topic2: 4个分区
C1: T1[P0,P1], T2[P0,P1] = 4个分区 😱
C2: T1[P2], T2[P2] = 2个分区
C3: T1[P3], T2[P3] = 2个分区
2️⃣ RoundRobin分配策略(RoundRobinAssignor)
轮流分配,更均衡!
工作原理:
- 把所有Topic的所有分区放一起
- 排个序
- 像发扑克牌一样,一人一个,轮着来!
示例:
Topic: orders,7个分区 (P0-P6)
Consumer Group: 3个消费者 (C1, C2, C3)
分配过程:
P0 → C1
P1 → C2
P2 → C3
P3 → C1 (回到C1)
P4 → C2
P5 → C3
P6 → C1
最终分配:
C1: [P0, P3, P6] ← 3个
C2: [P1, P4] ← 2个
C3: [P2, P5] ← 2个
生活比喻:🎴 真的像发扑克牌!你一张,我一张,他一张...
优点:
- ✅ 比Range更均衡
- ✅ 多Topic时也能保持均衡
缺点:
- ❌ 如果消费者订阅的Topic不同,可能出现分配不均
3️⃣ Sticky分配策略(StickyAssignor)⭐⭐⭐⭐⭐
最智能的策略:既均衡又稳定!
设计目标:
- 尽量均衡:和RoundRobin一样均衡
- 尽量粘性:Rebalance时,尽量保持之前的分配方案
为什么需要粘性?
想象一下:
初始分配:
C1: [P0, P1]
C2: [P2, P3]
C3: [P4, P5]
C3挂了,需要Rebalance!
如果用RoundRobin:
C1: [P0, P2, P4] ← P1没了,多了P2、P4
C2: [P1, P3, P5] ← P2没了,多了P1、P5
结果:所有消费者的分区都变了!😱
如果用Sticky:
C1: [P0, P1, P4] ← 保留P0、P1,只加P4
C2: [P2, P3, P5] ← 保留P2、P3,只加P5
结果:只改变最少的分区分配!✅
生活比喻:🪑 公司重新分座位,尽量让大家坐在原来的位置附近,而不是全部重新安排!
优点:
- ✅ 分配均衡
- ✅ Rebalance时减少分区迁移
- ✅ 减少状态丢失和重复消费
这是Kafka 2.4+的默认策略! 🎉
4️⃣ CooperativeSticky(协作式粘性)
Sticky的升级版!
区别:
- 传统Sticky:Rebalance时,所有消费者都停止消费 😴
- CooperativeSticky:Rebalance时,只停止需要迁移的分区 😎
图示:
C3挂了,P4和P5需要重新分配
传统方式:
C1: 停止消费 → 等待分配 → 重新开始
C2: 停止消费 → 等待分配 → 重新开始
CooperativeSticky:
C1: P0、P1继续消费,只有新加入的P4暂停一下
C2: P2、P3继续消费,只有新加入的P5暂停一下
生活比喻:🚗 修路时,不是封闭整条路,而是只封闭要修的那一段,其他地方正常通行!
🔄 Rebalance:消费者组的重新洗牌
什么是Rebalance?
Rebalance(再均衡) = 重新分配分区的过程 🔄
触发条件:
-
新消费者加入 👋
之前:C1、C2 之后:C1、C2、C3(新来的!) 需要重新分配! -
消费者离开 👋
之前:C1、C2、C3 C2挂了!💀 需要重新分配! -
消费者无响应 😴
C2处理太慢,心跳超时 Kafka以为它挂了 触发Rebalance! -
订阅的Topic分区数变化 📊
Topic从3个分区扩展到5个分区 需要重新分配! -
正则订阅时,匹配到新Topic 🎯
订阅模式:订阅所有以"order-"开头的Topic 新建了一个Topic: "order-vip" 触发Rebalance!
Rebalance的问题 😰
Rebalance很贵!
-
Stop The World 🛑
- 所有消费者停止消费
- 业务处理暂停
- 吞吐量降为0
-
状态丢失 💔
- 本地缓存失效
- 重新加载数据
-
重复消费 🔁
- offset可能还没提交
- 重新消费已处理的消息
生活比喻:🎬 电影院重新分配座位,所有人都要站起来,电影暂停,等重新分配完才能继续看!
如何减少Rebalance?💡
1. 调大心跳超时时间
# 心跳间隔
heartbeat.interval.ms=3000
# 会话超时(心跳超时)
session.timeout.ms=30000 # 默认10秒,可以调大到30秒
# 消费超时
max.poll.interval.ms=300000 # 5分钟
解释:
- 消费者定期发送心跳:"我还活着!" ❤️
- 如果超过
session.timeout.ms没心跳,认为它挂了 - 如果超过
max.poll.interval.ms没有poll消息,也认为它挂了
2. 减少单次拉取的消息数量
# 单次拉取最大消息数
max.poll.records=100 # 默认500,可以调小
原因:
- 如果一次拉取太多消息,处理时间过长
- 超过
max.poll.interval.ms,触发Rebalance - 调小后,处理更快,不会超时
3. 提高消费速度 ⚡
// 异步处理
consumer.poll(Duration.ofMillis(100)).forEach(record -> {
executor.submit(() -> {
processMessage(record);
});
});
4. 固定消费者数量
- 避免频繁加入/离开
- 使用容器编排时,固定副本数
5. 使用CooperativeSticky策略 🎯
partition.assignment.strategy=org.apache.kafka.clients.consumer.CooperativeStickyAssignor
🎓 知识总结卡片
生产者分区策略
┌─────────────────────────────────────┐
│ 指定分区:直接指定,精确控制 │
│ Key分区:相同Key进同一分区(常用) │
│ 轮询:无Key时轮流分配,最均衡 │
│ 自定义:自己的地盘自己做主 │
└─────────────────────────────────────┘
消费者分配策略
┌─────────────────────────────────────┐
│ Range:按范围分,简单但不均衡 │
│ RoundRobin:轮流分,更均衡 │
│ Sticky:均衡+粘性,减少迁移(推荐) │
│ CooperativeSticky:增量再均衡(更好)│
└─────────────────────────────────────┘
Rebalance触发条件
┌─────────────────────────────────────┐
│ ✅ 消费者加入 │
│ ✅ 消费者离开 │
│ ✅ 消费者心跳超时 │
│ ✅ 分区数变化 │
│ ✅ 正则订阅匹配到新Topic │
└─────────────────────────────────────┘
🎯 实战代码示例
生产者:使用Key分区
import org.apache.kafka.clients.producer.*;
import java.util.Properties;
public class KeyBasedProducer {
public static void main(String[] args) {
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("key.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
KafkaProducer<String, String> producer = new KafkaProducer<>(props);
// 相同用户的消息会进入同一个分区!
for (int i = 0; i < 10; i++) {
String userId = "user-" + (i % 3); // 3个用户
String message = "Message-" + i;
ProducerRecord<String, String> record =
new ProducerRecord<>(
"orders", // Topic
userId, // Key(重要!)
message // Value
);
producer.send(record, (metadata, exception) -> {
if (exception == null) {
System.out.printf("用户[%s]的消息发送到分区[%d],offset[%d]%n",
userId, metadata.partition(), metadata.offset());
}
});
}
producer.close();
}
}
/* 输出示例:
用户[user-0]的消息发送到分区[0],offset[0]
用户[user-1]的消息发送到分区[1],offset[0]
用户[user-2]的消息发送到分区[2],offset[0]
用户[user-0]的消息发送到分区[0],offset[1] ← 又是分区0!
用户[user-1]的消息发送到分区[1],offset[1] ← 又是分区1!
...
*/
消费者:配置Sticky策略
import org.apache.kafka.clients.consumer.*;
import java.util.*;
import java.time.Duration;
public class StickyConsumer {
public static void main(String[] args) {
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("group.id", "order-processing-group");
props.put("key.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");
// ⭐ 配置Sticky分配策略
props.put("partition.assignment.strategy",
"org.apache.kafka.clients.consumer.StickyAssignor");
// ⭐ 调优参数,减少Rebalance
props.put("session.timeout.ms", "30000"); // 30秒
props.put("heartbeat.interval.ms", "3000"); // 3秒
props.put("max.poll.interval.ms", "300000"); // 5分钟
props.put("max.poll.records", "100"); // 单次最多100条
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Arrays.asList("orders"));
// 监听Rebalance事件
consumer.subscribe(Arrays.asList("orders"), new ConsumerRebalanceListener() {
@Override
public void onPartitionsRevoked(Collection<TopicPartition> partitions) {
System.out.println("⚠️ Rebalance开始,失去分区: " + partitions);
// 提交offset,避免重复消费
consumer.commitSync();
}
@Override
public void onPartitionsAssigned(Collection<TopicPartition> partitions) {
System.out.println("✅ Rebalance完成,分配到分区: " + partitions);
}
});
try {
while (true) {
ConsumerRecords<String, String> records =
consumer.poll(Duration.ofMillis(100));
for (ConsumerRecord<String, String> record : records) {
System.out.printf("消费消息 - 分区:%d, Offset:%d, Key:%s, Value:%s%n",
record.partition(), record.offset(),
record.key(), record.value());
// 业务处理...
processMessage(record);
}
// 手动提交offset
consumer.commitAsync();
}
} finally {
consumer.close();
}
}
private static void processMessage(ConsumerRecord<String, String> record) {
// 业务逻辑处理
try {
Thread.sleep(100); // 模拟处理时间
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
自定义分区器:VIP专属通道
import org.apache.kafka.clients.producer.Partitioner;
import org.apache.kafka.common.Cluster;
import java.util.Map;
/**
* 自定义分区器:VIP用户走专属分区
*
* 业务需求:
* - VIP用户的消息走分区0(专属快速通道)
* - 普通用户的消息均匀分布在其他分区
*/
public class VIPPartitioner implements Partitioner {
private static final int VIP_PARTITION = 0;
@Override
public int partition(String topic, Object key, byte[] keyBytes,
Object value, byte[] valueBytes, Cluster cluster) {
// 获取该Topic的分区数量
int numPartitions = cluster.partitionCountForTopic(topic);
if (numPartitions == 1) {
return 0; // 只有1个分区,直接返回
}
// Key为null,随机分配到非VIP分区
if (key == null) {
return (int) (Math.random() * (numPartitions - 1)) + 1;
}
String keyStr = key.toString();
// VIP用户走专属分区0 🎩
if (keyStr.startsWith("VIP-") || keyStr.startsWith("vip-")) {
System.out.println("🎩 VIP用户 [" + keyStr + "] → VIP专属分区");
return VIP_PARTITION;
}
// 普通用户走其他分区(1到n-1)
int partition = (Math.abs(keyStr.hashCode()) % (numPartitions - 1)) + 1;
System.out.println("👤 普通用户 [" + keyStr + "] → 分区" + partition);
return partition;
}
@Override
public void close() {
// 清理资源(如果有的话)
}
@Override
public void configure(Map<String, ?> configs) {
// 初始化配置(如果需要的话)
}
}
// 使用自定义分区器
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
// ⭐ 指定自定义分区器
props.put("partitioner.class", "com.example.VIPPartitioner");
KafkaProducer<String, String> producer = new KafkaProducer<>(props);
// 测试
producer.send(new ProducerRecord<>("orders", "VIP-001", "VIP订单"));
producer.send(new ProducerRecord<>("orders", "user-123", "普通订单"));
🎭 常见面试题速答
Q1: 为什么要有分区?
A: 三个原因!
- 并行处理 - 多个消费者同时工作,提高吞吐量 🚀
- 水平扩展 - 单机存不下,加机器加分区 💪
- 容错能力 - 分区有副本,一个挂了还有备份 🛡️
Q2: 如何保证消息的顺序性?
A:
- 使用相同的Key - 相同Key的消息会进入同一个分区,分区内有序
- 单分区 - 整个Topic只有1个分区(不推荐,性能差)
- 单消费者 - 一个分区只能被一个消费者消费,自然有序
示例:
// 订单消息,用订单ID作为Key
producer.send(new ProducerRecord<>("orders", orderId, orderData));
// 同一个订单的所有操作,顺序保证!
Q3: 分区数量如何设置?
A: 经验公式!
分区数 = max(
期望吞吐量 / 单个生产者吞吐量,
期望吞吐量 / 单个消费者吞吐量
)
举例:
- 期望吞吐量:100 MB/s
- 单个生产者:10 MB/s
- 单个消费者:20 MB/s
分区数 = max(100/10, 100/20) = max(10, 5) = 10个分区
注意:
- ⚠️ 分区越多,Rebalance越慢
- ⚠️ 分区越多,Leader选举越慢
- ⚠️ 建议:单个Topic不超过100个分区
Q4: 消费者数量和分区数量的关系?
A:
消费者数 > 分区数 → 有消费者空闲(浪费资源)❌
消费者数 = 分区数 → 完美!每人一个分区 ✅
消费者数 < 分区数 → 一个消费者处理多个分区 ✅
最佳实践:
- 消费者数量 ≤ 分区数量
- 推荐:消费者数 = 分区数(充分并行)
图示:
3个分区,4个消费者:
P0 → C1
P1 → C2
P2 → C3
C4 (闲置,浪费!) ❌
3个分区,3个消费者:
P0 → C1
P1 → C2
P2 → C3 ✅ 完美!
3个分区,2个消费者:
P0 → C1
P1, P2 → C2 ✅ 也可以!
Q5: Rebalance有多慢?
A:
- 小集群(几个消费者):几百毫秒
- 大集群(几十个消费者):几秒到几十秒
- 超大集群(上百个):可能1分钟+ 😱
优化方法:
- 使用
CooperativeSticky策略 - 减少消费者的加入/离开频率
- 调优心跳和会话超时参数
Q6: 为什么推荐Sticky策略?
A: 举个例子!
场景:3个消费者,6个分区
初始分配:
C1: [P0, P1]
C2: [P2, P3]
C3: [P4, P5]
C3挂了!
RoundRobin重新分配:
C1: [P0, P2, P4] ← 变化:失去P1,得到P2、P4
C2: [P1, P3, P5] ← 变化:失去P2,得到P1、P5
变化率:4个分区迁移 / 6个分区 = 66% 😰
Sticky重新分配:
C1: [P0, P1, P4] ← 变化:只加P4
C2: [P2, P3, P5] ← 变化:只加P5
变化率:2个分区迁移 / 6个分区 = 33% 😊
好处:
- ✅ 减少状态迁移
- ✅ 减少缓存失效
- ✅ 减少重复消费
📝 调优检查清单
生产者端 ✅
□ 合理使用Key,保证相同业务Key进同一分区
□ 分区数设置合理(考虑吞吐量)
□ 自定义分区器(如果有特殊需求)
□ 设置合适的acks参数(可靠性vs性能)
□ 启用压缩(snappy/lz4)
消费者端 ✅
□ 消费者数 ≤ 分区数
□ 使用Sticky或CooperativeSticky策略
□ session.timeout.ms = 30000(避免心跳超时)
□ max.poll.interval.ms = 300000(避免消费超时)
□ max.poll.records = 100-500(根据业务调整)
□ 手动提交offset(更可控)
□ 监听Rebalance事件,及时处理
监控指标 📊
□ records-lag-max(消费延迟)
□ rebalance-latency-avg(Rebalance耗时)
□ records-consumed-rate(消费速率)
□ fetch-latency-avg(拉取延迟)
□ commit-latency-avg(提交延迟)
🎬 总结:一张图看懂所有!
Kafka分区策略全景图
┌─────────────────────────────────────────────────────────────┐
│ 生产者端 │
│ │
│ 消息 → 选择分区策略: │
│ ├─ 指定分区:直达 🎯 │
│ ├─ Key分区:hash(key) % n(常用)⭐ │
│ ├─ 轮询:无Key时轮流分配 🎰 │
│ └─ 自定义:自己掌控 🎨 │
│ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Kafka Topic │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Part 0 │ │ Part 1 │ │ Part 2 │ │ Part 3 │ │
│ │ Leader │ │ Leader │ │ Leader │ │ Leader │ │
│ │ [Msg...]│ │ [Msg...]│ │ [Msg...]│ │ [Msg...]│ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 消费者组 │
│ │
│ 分区分配策略: │
│ ├─ Range:按范围分,简单 📏 │
│ ├─ RoundRobin:轮流分,均衡 🎴 │
│ ├─ Sticky:均衡+粘性,减少迁移 ⭐ │
│ └─ CooperativeSticky:增量Rebalance,最优 🚀 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │Consumer 1│ │Consumer 2│ │Consumer 3│ │
│ │ P0, P1 │ │ P2 │ │ P3 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
↓
触发Rebalance的5种情况:
✅ 消费者加入/离开
✅ 消费者心跳超时
✅ 分区数变化
✅ 订阅变化
🎉 恭喜你!
你已经掌握了Kafka分区策略和消费者组负载均衡的全部知识!🎊
记住三个关键点:
- 生产者:用Key分区保证顺序性 🔑
- 消费者:用Sticky策略减少Rebalance影响 🏆
- 调优:合理设置超时参数,避免频繁Rebalance ⚙️
下次面试被问到,你就可以像这样回答:
"Kafka的分区策略主要有4种:指定分区、Key分区、轮询和自定义分区器。实际项目中我们最常用Key分区,因为它能保证相同Key的消息进入同一个分区,从而保证顺序性。
消费者端我们使用StickyAssignor策略,因为它在Rebalance时能尽量保持原有分配方案,减少分区迁移,避免状态丢失。
为了减少Rebalance的影响,我们会调大session.timeout.ms到30秒,并根据业务处理时间设置max.poll.interval.ms,同时限制max.poll.records避免单次处理时间过长。"
面试官:👍 "很好!你被录取了!"
📚 推荐阅读
- Kafka官方文档 - Partitioning
- Kafka官方文档 - Consumer Group
- KIP-54: Sticky Partition Assignment Strategy
- KIP-429: Kafka Consumer Incremental Rebalance Protocol
🎈 表情包时间 🎈
学完Kafka分区策略后的你:
😅 → 😐 → 🤔 → 😮 → 😃 → 🤩
(啥?)(有点懂)(原来如此)(我会了)(太棒了!)
vs
还没学之前的你:
😵💫
(分区?啥是分区?)
本文完 🎬
记得点赞👍 收藏⭐ 分享🔗
作者注:这篇文档写得我都饿了,感觉可以开一家"Kafka快递公司"了!🚚📦 如果你觉得这篇文章对你有帮助,请给我一个Star⭐,这是对我最大的鼓励!
版权声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。