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

  1. public ProducerRecord(String topic, Integer partition, Long timestamp, K key, V value) {
  2. if (topic == null)
  3. throw new IllegalArgumentException("Topic cannot be null");
  4. if (timestamp != null && timestamp < 0)
  5. throw new IllegalArgumentException("Invalid timestamp " + timestamp);
  6. this.topic = topic;
  7. this.partition = partition;
  8. this.key = key;
  9. this.value = value;
  10. this.timestamp = timestamp;
  11. }

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

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

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

我们来分析下partiton方法:

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

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

  1. public interface Partitioner extends Configurable {
  2. /**
  3. * Compute the partition for the given record.
  4. *
  5. * @param topic The topic name
  6. * @param key The key to partition on (or null if no key)
  7. * @param keyBytes The serialized key to partition on( or null if no key)
  8. * @param value The value to partition on or null
  9. * @param valueBytes The serialized value to partition on or null
  10. * @param cluster The current cluster metadata
  11. */
  12. public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster);
  13. /**
  14. * This is called when partitioner is closed.
  15. */
  16. public void close();
  17. }

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

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

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. 提名者周训,misc消失的文件

    下载附件是一个没有后缀的文件,一般这种东西,根据我这个菜狗的经验,直接就是丢进kali的binwalk一顿操作,最后果不其然,是发现了东西的 这里面可以看到一个小细节,就是在binwalk进行分离的时 ...

  2. 如何将k8s中的某些节点单独、仅给某些应用来使用

    1.概述 在k8s集群的使用场景中有这样的一种情况,某些机器只给某些特殊的应用来使用.那么,这个时候,需要有以下的2个条件来进行保障: 节点不允许其他的pod来使用 应用只允许被调度到该节点上 2.实 ...

  3. 2021年都要过去啦,你还在用Excel做数据可视化效果吗?

    2021年都要过去啦,你还在用Excel做数据可视化效果吗?古语有云,"工欲善其事,必先利其器",没有专业的工具,前期准备的再好也是白搭.现在运用数据可视化工具于经营活动中的企业是 ...

  4. 安装配置ingress-nginx支持https访问

    说明: ​ 1.k8s版本:v1.23: ​ 2.内网测试环境1台master,2台node节点,使用 DaemonSet+HostNetwork+nodeSelector 方式部署 ingress- ...

  5. 【Windows身份认证】NTLM

    前言 前几天自己在学习域渗透时突然对Windows的身份认证机制产生了兴趣,但看了好几天自己还是懵懵懂懂,期间自己看了许多师傅的优质文章,也做了一些例子的复现,于是有了这篇文章,可以说是自己的笔记或总 ...

  6. linux中docker容器安装vi命令详解

    在使用docker容器时,同时你docker里的系统正好是debian或ubuntu的时候,有时候里边没有安装vim,敲vim命令时提示说:vim: command not found,这个时候就需要 ...

  7. JZ-020-包含 min 函数的栈

    包含 min 函数的栈 题目描述 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1)). 题目链接: 包含 min 函数的栈 代码 import jav ...

  8. Springboot循环依赖实践纪实

    测试的Springboot版本: 2.6.4,禁止了循环依赖,但是可以通过application.yml开启(哈哈) @Lazy注解解决循环依赖 情况一:只有简单属性关系的循环依赖 涉及的Bean: ...

  9. pygame写俄罗斯方块

    代码搬运修改自python编写俄罗斯方块 更新时间:2020年03月13日 09:39:17 作者:勤勉之 from tkinter import * from random import * imp ...

  10. 微信小程序节流使用方法

    函数节流: 英文 throttle 有节流阀的意思.大致意思也是 节约触发的频率 那么,函数节流,真正的含义是:单位时间n秒内,第一次触发函数并执行,以后 n秒内不管触发多少次,都不执行.直到下一个单 ...