kafka发送一个消息的时候需要封装成一个ProducerRecord :

public ProducerRecord(String topic, Integer partition, Long timestamp, K key, V value) {
if (topic == null)
throw new IllegalArgumentException("Topic cannot be null");
if (timestamp != null && timestamp < 0)
throw new IllegalArgumentException("Invalid timestamp " + timestamp);
this.topic = topic;
this.partition = partition;
this.key = key;
this.value = value;
this.timestamp = timestamp;
}

我们需要关注的是partition和key。

kafka在调用send的时候实际上是将消息放到了内存中,并没有发送出去。在放到内存队列之前,会计算消息应该放到哪个partiton中

private Future<RecordMetadata> doSend(ProducerRecord<K, V> record, Callback callback) {
// 忽略
int partition = partition(record, serializedKey, serializedValue, metadata.fetch()); // partiton用来计算书消息具体放置的partiton
//忽略
if (result.batchIsFull || result.newBatchCreated) {
log.trace("Waking up the sender since topic {} partition {} is either full or getting a new batch", record.topic(), partition);
this.sender.wakeup();
}
return result.future;
// 忽略
}

我们来分析下partiton方法:

private int partition(ProducerRecord<K, V> record, byte[] serializedKey , byte[] serializedValue, Cluster cluster) {
Integer partition = record.partition(); // ProducerRecord中partiton参数 if (partition != null) {
List<PartitionInfo> partitions = cluster.partitionsForTopic(record.topic());
int lastPartition = partitions.size() - 1;
// they have given us a partition, use it
if (partition < 0 || partition > lastPartition) {
throw new IllegalArgumentException(String.format("Invalid partition given with record: %d is not in the range [0...%d].", partition, lastPartition));
}
return partition; // 指定了partiton,则消息发送到该指定的partiton
} // 否则使用partitioner根据ProducerRecord的key参数来计算发送的partiton
return this.partitioner.partition(record.topic(), record.key(), serializedKey, record.value(), serializedValue,
cluster);
}

可以通过在配置中指定“partitioner.class”配置项使用自定义的partitioner,自定义的partitioner需要实现Partitioner接口:

public interface Partitioner extends Configurable {

    /**
* Compute the partition for the given record.
*
* @param topic The topic name
* @param key The key to partition on (or null if no key)
* @param keyBytes The serialized key to partition on( or null if no key)
* @param value The value to partition on or null
* @param valueBytes The serialized value to partition on or null
* @param cluster The current cluster metadata
*/
public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster); /**
* This is called when partitioner is closed.
*/
public void close(); }

如果没有指定“partitioner.class”配置项则使用默认的partitioner:DefaultPartitioner。我们来看下DefaultPartitioner的分配方法

public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) {
List<PartitionInfo> partitions = cluster.partitionsForTopic(topic); // 获取partiton列表,该列表是更新metadata的时候获取的,默认每30s更新一次metadata
int numPartitions = partitions.size();
if (keyBytes == null) { // 如果ProducerRecord没有传入key,则从一个随机数开始,采用round-robin方式
int nextValue = counter.getAndIncrement(); // counter被初始化为一个随机值,每次递增
List<PartitionInfo> availablePartitions = cluster.availablePartitionsForTopic(topic);
if (availablePartitions.size() > 0) {
int part = DefaultPartitioner.toPositive(nextValue) % availablePartitions.size();
return availablePartitions.get(part).partition();
} else {
// no partitions are available, give a non-available partition
return DefaultPartitioner.toPositive(nextValue) % numPartitions;
}
} else { // 对 keyBytes 进行 hash 选出一个 patition
// hash the keyBytes to choose a partition
return DefaultPartitioner.toPositive(Utils.murmur2(keyBytes)) % numPartitions;
}
}

kafka指定partiton生产的更多相关文章

  1. Kafka下的生产消费者模式与订阅发布模式

    原文:https://blog.csdn.net/zwgdft/article/details/54633105   在RabbitMQ下的生产消费者模式与订阅发布模式一文中,笔者以“数据接入”和“事 ...

  2. docker搭建kafka环境&&Golang生产和消费

    docker 搭建kafka环境 version: '2' services: zk1: image: confluentinc/cp-zookeeper:latest hostname: zk1 c ...

  3. 关于怎么获取kafka指定位置offset消息(转)

    1.在kafka中如果不设置消费的信息的话,一个消息只能被一个group.id消费一次,而新加如的group.id则会被“消费管理”记录,并指定从当前记录的消息位置开始向后消费.如果有段时间消费者关闭 ...

  4. ELK+kafka+filebeat搭建生产ELFK集群

    文章原文 ELK 架构介绍 集群服务版本 服务 版本 java 1.8.0_221 elasticsearch 7.10.1 filebeat 7.10.1 kibana 7.10.1 logstas ...

  5. python操作kafka(confluent_kafka 生产)

    #!/usr/bin/python # -*- coding:utf-8 -*- from confluent_kafka import Producer import json import tim ...

  6. kafka指定partition的分区规则

    博客地址:https://www.cnblogs.com/gnivor/p/5318319.html

  7. Python 基于Python结合pykafka实现kafka生产及消费速率&主题分区偏移实时监控

    基于Python结合pykafka实现kafka生产及消费速率&主题分区偏移实时监控   By: 授客 QQ:1033553122   1.测试环境 python 3.4 zookeeper- ...

  8. 二十二、Hadoop学记笔记————Kafka 基础实战 :消费者和生产者实例

    kafka的客户端也支持其他语言,这里主要介绍python和java的实现,这两门语言比较主流和热门 图中有四个分区,每个图形对应一个consumer,任意一对一即可 获取topic的分区数,每个分区 ...

  9. Kafka基础

    简介 #概念:消息中间件(消息系统)      //消息系统分类:         点对点 消息队列(peer-to-peer)         发布/订阅 消息队列 消费者在消费时,是通过pull ...

随机推荐

  1. linux下用crunch工具生成密码

    crunch是一款linux下的压缩后仅仅38k的小程序,crunch程序在2004年及以前由email为的作者编写mimayin@aciiid.ath.cx,后续版本由bofh28@gmail.co ...

  2. BI工具做数据可视化项目频频失败的原因

    现如今数据可视化可谓是非常之火,随着硬件价格的一降再降,仿佛做数据可视化项目,你没有数据大屏,你就没有逼格.理想很丰满,现实很骨感,并不是每一个数据可视化项目都能够成功.数据可视化项目的进行,无外乎是 ...

  3. 【C# .Net GC】强制垃圾回收 和System GC

    属性 GC.MaxGeneration:获取系统当前支持的最大代数. 方法 GC.GetTotalMemory(bool forceFullCollection) 方法  true表示该方法先做垃圾收 ...

  4. 【C# IO 操作 】详解去掉字符顺序标记(BOM)头的方法

    类似WINDOWS自带的记事本等软件,在保存一个以UTF-8编码的文件时,会在文件开始的地方插入三个不可见的字符(0xEF 0xBB 0xBF,即BOM).它是一串隐藏的字符,用于让记事本等编辑器识别 ...

  5. window 消息传递机制【复杂版本】

    一.消息概述     众人周知,window系统是一个消息驱动的系统, windows操作系统本身有自己的消息队列称做系统消息队列(操作系统队列),消息循环,它捕捉键盘,鼠标的动作生成消息,并将这个消 ...

  6. ElasticSearch学习笔记(详细)

    目录 ElasticSearch概述 ElasticSearch入门 安装 基本操作 查看es相关信息 索引操作 文档操作 bulk批量API 进阶检索 Search API Query DSL 分词 ...

  7. SpringMVC教程--Idea中使用Maven创建SpringMVC项目

    1.新建项目 参照idea教程中的创建maven项目https://www.cnblogs.com/daxiang2008/p/9061653.html 2.POM中加入依赖包 (1)指定版本 (2) ...

  8. Qt:QWebChannel

    0.说明 QWebChannel的作用是将QObject展示给的HTML客户. QWebChannel是连接C++应用和HTML/JS应用的桥梁.通过把一个QObject传入QWebChannel并在 ...

  9. c# 导出Excel模板(在项目中有现成的Excel模板)

    在项目中会有导出模板功能,把现成的Excel模板导出去填写之后再进行导入,这里说说怎么导出模板: 模板存放位置: 点击导出模板按钮:  private string currentPath = Pat ...

  10. 禁用所有控制台console.log()打印

    在前端dev的环境下,经常会用到console.log()进行调试,以方便开发, 而在产品release的版本中,又不合适在浏览器的console中输出那么多的调试信息. 但是会经常因为没有删除这些开 ...