Kafka 自定义指定消息partition策略规则及DefaultPartitioner源码分析
一.概述
kafka默认使用DefaultPartitioner类作为默认的partition策略规则,具体默认设置是在ProducerConfig类中(如下图)

二.DefaultPartitioner.class 源码分析
1.类关系图

2.源码分析
public class DefaultPartitioner implements Partitioner { //缓存map key->topic value->RandomNumber 随机数 private final ConcurrentMap<String, AtomicInteger> topicCounterMap = new ConcurrentHashMap<>(); //实现Configurable接口里configure方法, public void configure(Map<String, ?> configs) {} //策略核心方法 public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) { //根据topic获取对应的partition List<PartitionInfo> partitions = cluster.partitionsForTopic(topic); int numPartitions = partitions.size(); //如果key是null的话 if (keyBytes == null) { int nextValue = nextValue(topic); //获取可用的分区数量 List<PartitionInfo> availablePartitions = cluster.availablePartitionsForTopic(topic); //如果存在可用的分区 if (availablePartitions.size() > 0) { //消息随机分布到topic的可用partition中 int part = Utils.toPositive(nextValue) % availablePartitions.size(); return availablePartitions.get(part).partition(); } else { //不存在可用分区 随机分配一个不可用的partition中 return Utils.toPositive(nextValue) % numPartitions; } } else { //使用自己的 hash 算法对 key 取 hash 值,使用 hash 值与 partition 数量取模,从而确定发送到哪个分区。 return Utils.toPositive(Utils.murmur2(keyBytes)) % numPartitions; } } private int nextValue(String topic) { //获取topic 获取对应的随机数 AtomicInteger counter = topicCounterMap.get(topic); if (null == counter) { //获取一个随机值 counter = new AtomicInteger(ThreadLocalRandom.current().nextInt()); //缓存到topicCounterMap中 AtomicInteger currentCounter = topicCounterMap.putIfAbsent(topic, counter); if (currentCounter != null) { counter = currentCounter; } } //获取 并且实现自增,最终效果是实现轮训插入partition return counter.getAndIncrement(); } public void close() {} }
三.自定义Partition
自定义selfPartitioner类,并且实现Partitioner接口,重写partition和close方法
public class SelfPartitioner implements Partitioner { @Override public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) { //TODO 自定义数据分区策略 return 0; } @Override public void close() { } @Override public void configure(Map<String, ?> configs) { } }
四.生产者中使用自定义的Partition
在初始化producer时候,配置项中指定对应的partitioner
props.put("partitioner.class", "org.jake.partitioner.selfPartitioner");