消息在通过send()方法发往broker的过程中,有可能需要经过拦截器(Interceptor)、序列化器(Serializer)和分区器(Partitioner)的一系列作用之后才能被真正地发往 broker
- 如果消息ProducerRecord中没有指定partition字段,那么就需要依赖分区器,根据key这个字段来计算partition的值。分区器的作用就是为消息分配分区。
- Kafka中提供的默认分区器是org.apache.kafka.clients.producer.internals.DefaultPartitioner,它实现了
org.apache.kafka.clients.producer.Partitioner接口,这个接口中定义了2个方法,具体如下所示。
其中partition()方法用来计算分区号,返回值为int类型。partition()方法中的参数分别表示主题、键、序列化后的键、值、序列化后的值,以及集群的元数据信息,通过这些信息可以实现功能丰富的分区器。close()方法在关闭分区器的时候用来回收一些资源。其中如果 key 不为 null,那么默认的分区器会对 key 进行哈希(采用MurmurHash2算法,具备高运算性能及低碰撞率),最终根据得到的哈希值来计算分区号,拥有相同key的消息会被写入同一个分区。如果key为null,那么消息将会以轮询的方式发往主题内的各个可用分区。
分区策略
分区策略分为两种,一种是默认分区策略
- 序列化key存在时,对其采用murmur2 hash算法,再对总分区数取模。得到分区数。
- 序列化key不存在时,则采用(轮询,round robin) 可用分区数大于0时,用线程安全生成的随机数的绝对值 对 可用分区数 取模,在总分区列表中,找到对应的分区数。
可用分区数等于0时,用线程安全生成的随机数的绝对值 对 总分区数 取模,得到分区数。
另一种是自定义分区:
- 哈希分区:kafka允许为每条消息定义消息键,简称为key。一旦消息被定义了key,那么一个键的哈希值是固定的,根据自定的哈希算法,就可以保证同一个key的所有消息都进入到相同的分区里面,,
- 轮询分区:也称Round-robin策略,即顺序分配。比如一个topic下有3个分区,那么第一条消息被发送到分区0,第二条被发送到分区1,第三条被发送到分区2,以此类推。当生产第四条消息时又会重新开始。
- 随机分区:也称Randomness策略。所谓随机就是我们随意地将消息放置在任意一个分区上