key为null时Kafka会将消息发送给哪个分区?

当你编写kafka Producer时, 会生成KeyedMessage对象。

1
KeyedMessage<K, V> keyedMessage = new KeyedMessage<>(topicName, key, message)

这里的key值可以为空,在这种情况下, kafka会将这个消息发送到哪个分区上呢?依据Kafka官方的文档, 默认的分区类会随机挑选一个分区:

The third property "partitioner.class" defines what class to use to determine which Partition in the Topic the message is to be sent to. This is optional, but for any non-trivial implementation you are going to want to implement a partitioning scheme. More about the implementation of this class later. If you include a value for the key but haven't defined a partitioner.class Kafka will use the default partitioner. If the key is null, then the Producer will assign the message to a random Partition.

但是这句话相当的误导人。

从字面上来讲,这句话没有问题, 但是这里的随机是指在参数"topic.metadata.refresh.ms"刷新后随机选择一个, 这个时间段内总是使用唯一的分区。 默认情况下每十分钟才可能重新选择一个新的分区。 但是相信大部分的程序员和我一样, 都理解成每个消息都会随机选择一个分区。
可以查看相关的代码:

key为null时Kafka会将消息发送给哪个分区?

当你编写kafka Producer时, 会生成KeyedMessage对象。

1
KeyedMessage<K, V> keyedMessage = new KeyedMessage<>(topicName, key, message)

这里的key值可以为空,在这种情况下, kafka会将这个消息发送到哪个分区上呢?依据Kafka官方的文档, 默认的分区类会随机挑选一个分区:

The third property "partitioner.class" defines what class to use to determine which Partition in the Topic the message is to be sent to. This is optional, but for any non-trivial implementation you are going to want to implement a partitioning scheme. More about the implementation of this class later. If you include a value for the key but haven't defined a partitioner.class Kafka will use the default partitioner. If the key is null, then the Producer will assign the message to a random Partition.

但是这句话相当的误导人。

从字面上来讲,这句话没有问题, 但是这里的随机是指在参数"topic.metadata.refresh.ms"刷新后随机选择一个, 这个时间段内总是使用唯一的分区。 默认情况下每十分钟才可能重新选择一个新的分区。 但是相信大部分的程序员和我一样, 都理解成每个消息都会随机选择一个分区。
可以查看相关的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private def getPartition(topic: String, key: Any, topicPartitionList: Seq[PartitionAndLeader]): Int = {
val numPartitions = topicPartitionList.size
if(numPartitions <= 0)
throw new UnknownTopicOrPartitionException("Topic " + topic + " doesn't exist")
val partition =
if(key == null) {
// If the key is null, we don't really need a partitioner
// So we look up in the send partition cache for the topic to decide the target partition
val id = sendPartitionPerTopicCache.get(topic)
id match {
case Some(partitionId) =>
// directly return the partitionId without checking availability of the leader,
// since we want to postpone the failure until the send operation anyways
partitionId
case None =>
val availablePartitions = topicPartitionList.filter(_.leaderBrokerIdOpt.isDefined)
if (availablePartitions.isEmpty)
throw new LeaderNotAvailableException("No leader for any partition in topic " + topic)
val index = Utils.abs(Random.nextInt) % availablePartitions.size
val partitionId = availablePartitions(index).partitionId
sendPartitionPerTopicCache.put(topic, partitionId)
partitionId
}
} else
partitioner.partition(key, numPartitions)
if(partition < 0 || partition >= numPartitions)
throw new UnknownTopicOrPartitionException("Invalid partition id: " + partition + " for topic " + topic +
"; Valid values are in the inclusive range of [0, " + (numPartitions-1) + "]")
trace("Assigning message of topic %s and key %s to a selected partition %d".format(topic, if (key == null) "[none]" else key.toString, partition))
partition
}

如果key为null, 它会从sendPartitionPerTopicCache查选缓存的分区, 如果没有,随机选择一个分区,否则就用缓存的分区。

LinkedIn工程师Guozhang Wang在邮件列表中解释了这一问题,
最初kafka是按照大部分用户理解的那样每次都随机选择一个分区, 后来改成了定期选择一个分区, 这是为了减少服务器段socket的数量。不过这的确很误导用户,据称0.8.2版本后又改回了每次随机选取。但是我查看0.8.2的代码还没看到改动。

所以,如果有可能,还是为KeyedMessage设置一个key值吧。

LinkedIn工程师Guozhang Wang在邮件列表中解释了这一问题,如果key为null, 它会从sendPartitionPerTopicCache查选缓存的分区, 如果没有,随机选择一个分区,否则就用缓存的分区。

最初kafka是按照大部分用户理解的那样每次都随机选择一个分区, 后来改成了定期选择一个分区, 这是为了减少服务器段socket的数量。不过这的确很误导用户,据称0.8.2版本后又改回了每次随机选取。但是我查看0.8.2的代码还没看到改动。

所以,如果有可能,还是为KeyedMessage设置一个key值吧。

from:http://colobu.com/2015/01/22/which-kafka-partition-will-keyedMessages-be-sent-to-if-key-is-null/

kafka负载均衡相关资料收集(一)的更多相关文章

  1. kafka负载均衡相关资料收集(三)

    apache kafka系列之Producer处理逻辑 下文是转载的,原文链接地址:点这儿 [转] Kafka ProducerKafka Producer处理逻辑kafka生产者处理逻辑apache ...

  2. kafka负载均衡相关资料收集(二)

    [转]关于kafka producer 分区策略的思考 from:http://blog.csdn.net/ouyang111222/article/details/51086037 今天跑了一个简单 ...

  3. AssetBundle机制相关资料收集

    原地址:http://www.cnblogs.com/realtimepixels/p/3652075.html AssetBundle机制相关资料收集 最近网友通过网站搜索Unity3D在手机及其他 ...

  4. FastAdmin 导出 Excel 相关资料收集 (2018-08-14)

    FastAdmin 导出 Excel 相关资料收集 导出 Excel 文件时身份证号变成科学计数法怎么办? https://forum.fastadmin.net/thread/1346 姊妹篇 Fa ...

  5. FastAdmin 导入 Excel 相关资料收集 (2018-08-14)

    FastAdmin 导入 Excel 相关资料收集 新版本一键CRUD后自带导入功能,但是默认被禁用,如何启动 https://forum.fastadmin.net/thread/540 Excel ...

  6. Kafka 负载均衡在 vivo 的落地实践

    ​vivo 互联网服务器团队-You Shuo 副本迁移是Kafka最高频的操作,对于一个拥有几十万个副本的集群,通过人工去完成副本迁移是一件很困难的事情.Cruise Control作为Kafka的 ...

  7. iOS10以及xCode8相关资料收集

    兼容iOS 10 资料整理笔记 源文:http://www.jianshu.com/p/0cc7aad638d9 1.Notification(通知) 自从Notification被引入之后,苹果就不 ...

  8. nginx 负载均衡相关知识

    Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器. Nginx 是由 Igor Sysoev ...

  9. F5 负载均衡 相关资源

    F5负载均衡之检查命令的说明http://net.zdnet.com.cn/network_security_zone/2010/0505/1730942.shtml F5培训http://wenku ...

随机推荐

  1. VS调试快捷键

    VS调试快捷键   命令名 快捷键 说明 调试.应用代码更改 Alt + F10 启动生成操作,利用它可以通过“编辑并继续”功能应用对正在调试的代码所作的更改. 调试.自动窗口 Ctrl + D,Ct ...

  2. CNN-卷积层和池化层学习

    卷积神经网络(CNN)由输入层.卷积层.激活函数.池化层.全连接层组成,即INPUT-CONV-RELU-POOL-FC (1)卷积层:用它来进行特征提取,如下: 输入图像是32*32*3,3是它的深 ...

  3. cmake 学习笔记(三) (转)

    接前面的 Cmake学习笔记(一) 与 Cmake学习笔记(二) 继续学习 cmake 的使用. 学习一下cmake的 finder. finder是神马东西? 当编译一个需要使用第三方库的软件时,我 ...

  4. 5个经典的JavaScript面试题

    在IT界中公司对JavaScript开发者的要求还是比较高的,但是如果JavaScript开 发者的技能和经验都达到了一定的级别,那他们还是很容易跳到优秀的公司的,当然薪水就更不是问题了.但是在面试之 ...

  5. Mybatis之使用注解开发CRUD

    上一篇演示了怎样使用XML来操作Mybatis实现CRUD,可是大量的XML配置文件的编写是很烦人的.因此 Mybatis也提供了基于注解的配置方式,以下我们来演示一下使用接口加注解来实现CRUD的的 ...

  6. DevExpress去除多国语言包

    DevExpress作为windows开发中较为强大的第三方组件,能极大的提高编程效率和界面效果.但也要引用它较多的dll文件,它专门有个查看dll程序集依赖的工具,在VS的工具菜单下: 在VS的工具 ...

  7. iOS 按钮拖动。

    -(void)testMove { moveBtn = [[UIButton alloc ]init]; moveBtn.frame = CGRectMake(0, 30, 60, 60); move ...

  8. Swift语言精要 - 序列化和反序列化

    在swift中你可以把一个对象转换成为数据,你所要做的就是 首先,你需要让对象实现NSObject和NSCoding协议. 其次,实现以下两个方法: encodeWithCoder init(code ...

  9. 简单实用的extend对象合并

    /** * 合并对象 * 示例:o = extend({ a: 'a' }, o); */ function extend(s, t) { if (!s) { return {}; } if (!s) ...

  10. 【转】一些linux基础命令

    学习Linux,其实很多基础命令很重要. 不论多么复杂的shell或者命令组合,都是一个一个的拼接组合命令拼接而成: 大号一个基本功,遇到需要的场景,信手拈来,随意组合拼接,是非常重要的. 恰好看到一 ...