6.Kafka-生产者发送到Broker分区策略和常见配置

分区选择策略

Kafka中生产者发送到Broker分区,分区选择策略分为四种。指定Partition ID、指定了Key和轮询算法和自定义分区策略。

指定Partition ID

拥有最高优先级的分区选择策略。即使指定了对应的Key,也会遵循Partition ID选择的策略。

java 复制代码
ProducerRecord<String, String> record = 
    new ProducerRecord<>("my-topic", 2, "key", "value");
// 这条消息将直接发送到分区2,忽略Key值

指定Key

未指定Partition ID,当使用Key去选择分区,就需要使用hash算法,确定目标分区。

java 复制代码
ProducerRecord<String, String> record = 
    new ProducerRecord<>("my-topic", "user-123", "order data");
// 通过 hash("user-123") % 分区数 确定目标分区

这里的Hash算法并不是Java的hashCode。而是使用了MurmurHash2的算法。让相同Key的消息总是发送到同一个分区,保证同一业务实体的消息有序性。

轮询算法

轮询算法是Kafka默认的策略。能够实现负载均衡,让消息能够均匀的分布到所有的分区,也能够最大化吞吐量,避免单个分区成为热点的问题。

java 复制代码
ProducerRecord<String, String> record = 
    new ProducerRecord<>("my-topic", "value only");
// 使用round-robin轮询算法

自定义分区策略

自定义分区策略一般来说只有特殊的业务才会使用的到。需要实现Partitioner到接口

java 复制代码
// 实现Partitioner接口
public class CustomPartitioner implements Partitioner {
    @Override
    public int partition(String topic, Object key, 
                         byte[] keyBytes, Object value, 
                         byte[] valueBytes, Cluster cluster) {
        // 自定义分区逻辑
        List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
        int numPartitions = partitions.size();
        
        if (keyBytes == null) {
            // 没有Key时使用轮询
            return roundRobinPartition(topic, numPartitions);
        } else {
            // 有Key时使用自定义逻辑
            return customHash(keyBytes) % numPartitions;
        }
    }
}

流程图

核心配置参数

bootstrap.servers - 集群地址

java 复制代码
# 格式:host1:port1,host2:port2,...
bootstrap.servers=localhost:9092,localhost:9093,localhost:9094

最主要的作用:

生产者用于发现集群中所有的Broker的初始连接列表

只需要提供部分Broker地址,生产者会自动发现集群完整拓扑

建议至少提供多个Broker地址,避免单点故障的问题。

acks - 消息确认机制

acks消息确认机制分为三种模式。0、1和all/-1

acks = 0

从可靠性上,是三种模式中最低的,Leader写入缓存就返回,不等待任何确认。

从性能上,是三种模式中最高的,零等待以及最高的吞吐。

从适用场景上,适合日志收集,指标上报等可容忍数据丢失的场景。

acks = 1

从可靠性上,是三种模式中中等的,Leader写入成功(落盘)即返回

从性能上,是三种模式中较高的,需要等待Leader确认。

从适用场景上,适合大多数业务场景,平衡性能与可靠性。

acks = all/-1

从可靠性上,是三种模式中最高的,等待所有ISR副本同步成功。

从性能上,是三种模式中最低的,需要等待所有副本确认。

从适用场景上,适合金融交易、重要订单等要求强一致的场景。

retriesretry.backoff.ms - 重试机制

主要讲三个参数。retries、retry.backoff.ms和enable.idempotence

retries是指重试次数,默认是Integer.MAX_VALUE。我最常使用是3次

retry.backoff.ms是重试的间隔,默认是100ms。我最常使用的是1000ms

enable.idempotence是启用幂等性,避免重试导致消息重复问题。

PS:这里重试需要注意一下:

Kafka的重试是幂等的,当我们的enable.idempotence是true。

重试可能会导致消息顺序改变,需要max.in.flight.requests.per.connection=1来保证顺序

重试只对可恢复错误有效,比如说Leader选举和网络抖动

批处理优化参数

批处理优化参数也主要是三个。batch.size、linger.ms和buffer.memory。

batch.size

batch.size的默认值为16KB,它的作用是单个批次的最大字节数。

调优建议:根据消息的大小进行调整,太小,就增加了请求数,太大,就增加了延迟。

linger.ms

linger.ms的默认值为0ms,它的作用是批次在发送前的最大等待时间。增加这个值,能够提高吞吐,但是会增加延迟,一般来说都设置为5ms到100ms比较合理。

buffer.memory

buffer.memory到默认值是32MB,它的作用是生产者缓冲区的总内存大小。调优的时候建议根据监控缓冲区的使用情况,避免阻塞。

场景建议参数

当场景是高吞吐场景时

XML 复制代码
batch.size=32768      # 32KB
linger.ms=20          # 等待20ms
buffer.memory=67108864 # 64MB

当场景是低延时场景时

XML 复制代码
batch.size=16384      # 16KB  
linger.ms=0           # 立即发送
buffer.memory=33554432 # 32MB

当缓冲区的使用率到达95%或超过这个数值的时候,需要考虑增加buffer.memory。

相关推荐
小股虫7 小时前
分布式事务:在增长中台,我们如何做到“发出去的内容”和“记录的数据”不打架?
分布式·微服务·云原生·架构·团队建设·方法论
是三好7 小时前
分布式事务seata
java·分布式·seata
optimistic_chen8 小时前
【Redis 系列】常用数据结构---Hash类型
linux·数据结构·redis·分布式·哈希算法
yuankunliu8 小时前
【分布式事务】4、分布式事务Seata的高级应用详解
分布式
java1234_小锋8 小时前
ZooKeeper集群中服务器之间是怎样通信的?
分布式·zookeeper·云原生
昌sit!10 小时前
hadoop集群搭建
大数据·hadoop·分布式
左灯右行的爱情13 小时前
Kafka专辑- 消息队列是什么
分布式·kafka
小股虫13 小时前
让系统“杀不死”:同步与异步场景下的弹性设计模式手册
分布式·微服务·设计模式·架构·团队建设·方法论
yumgpkpm13 小时前
银行的数据智能平台和Cloudera CDP 7.3(CMP 7.3)的技术对接
数据库·人工智能·hive·hadoop·elasticsearch·数据挖掘·kafka
前端世界14 小时前
鸿蒙分布式权限管理实战指南:架构原理 + 可运行 Demo
分布式·架构·harmonyos