Kafka学习笔记(二):Partition分发策略
kafka版本0.8.2.1
Java客户端版本0.9.0.0
为了更好的实现负载均衡和消息的顺序性,Kafka Producer可以通过分发策略发送给指定的Partition。Kafka保证在partition中的消息是有序的。Kafka Java客户端有默认的Partitioner。实现如下:
public int partition(ProducerRecord<byte[], byte[]> record, Cluster cluster) {
List partitions = cluster.partitionsForTopic(record.topic());
int numPartitions = partitions.size();
if(record.partition() != null) {
if(record.partition().intValue() >= 0 && record.partition().intValue() < numPartitions) {
return record.partition().intValue();
} else {
throw new IllegalArgumentException("Invalid partition given with record: " + record.partition() + " is not in the range [0..." + numPartitions + "].");
}
} else if(record.key() == null) {
int nextValue = this.counter.getAndIncrement();
List availablePartitions = cluster.availablePartitionsForTopic(record.topic());
if(availablePartitions.size() > 0) {
int part = Utils.abs(nextValue) % availablePartitions.size();
return ((PartitionInfo)availablePartitions.get(part)).partition();
} else {
return Utils.abs(nextValue) % numPartitions;
}
} else {
return Utils.abs(Utils.murmur2((byte[])record.key())) % numPartitions;
}
}
从源码可以看出,首先获取topic的所有Patition,如果客户端不指定Patition,也没有指定Key的话,使用自增长的数字取余数的方式实现指定的Partition。这样Kafka将平均的向Partition中生产数据。测试代码如下:
Producer:
String topic = "haoxy1";
int i = 0;
Properties props = new Properties();
props.put("bootstrap.servers", "10.23.22.237:9092,10.23.22.238:9092,10.23.22.239:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
KafkaProducer<String, String> producer = new KafkaProducer<String, String>(props);
System.out.println("partitions count " + producer.partitionsFor(topic));
while(true) {
String msg = "test"+i++;
ProducerRecord<String, String> producerRecord = new ProducerRecord<String, String>(topic, msg);
producer.send(producerRecord);
System.out.println("send " + msg);
Thread.sleep(5000);
}
Consumer:
String topic = "haoxy1";
Properties props = new Properties();
props.put("zookeeper.connect", "10.23.22.237:2181,10.23.22.238:2181,10.23.22.239:2181");
props.put("group.id", "cg.nick");
props.put("consumer.id", "c.nick");
Map<String, Integer> topicCountMap = new HashMap<String, Integer>();
topicCountMap.put(topic, 3);
ConsumerConfig consumerConfig = new ConsumerConfig(props);
ConsumerConnector consumer = Consumer.createJavaConsumerConnector(consumerConfig);
Map<String, List<KafkaStream<byte[], byte[]>>> consumerMap = consumer.createMessageStreams(topicCountMap);
List<KafkaStream<byte[], byte[]>> streams = consumerMap.get(topic);
ExecutorService executor = Executors.newFixedThreadPool(3);
for (final KafkaStream stream : streams) {
executor.submit(new Runnable() {
public void run() {
ConsumerIterator<byte[], byte[]> it = stream.iterator();
while (it.hasNext()) {
MessageAndMetadata<byte[], byte[]> mm = it.next();
System.out.println(String.format("partition = %s, offset = %d, key = %s, value = %s", mm.partition(), mm.offset(), mm.key(), new String(mm.message())));
}
}
});
}
从测试结果结果看出,是平均分配的:
partition = 1, offset = 416, key = null, value = test9
partition = 0, offset = 386, key = null, value = test10
partition = 2, offset = 454, key = null, value = test11
partition = 1, offset = 417, key = null, value = test12
partition = 0, offset = 387, key = null, value = test13
partition = 2, offset = 455, key = null, value = test14
partition = 1, offset = 418, key = null, value = test15
partition = 0, offset = 388, key = null, value = test16
如果想要控制发送的partition,则有两种方式,一种是指定partition,另一种就是根据Key自己写算法。继承Partitioner接口,实现其partition方法。并且配置启动参数
props.put("partitioner.class","TestPartitioner")。
比如需要实现
key=’aaa’ 的都进partition 0
key=’bbb’ 的都进partition 1
key=’bbb’ 的都进partition 2
public class TestPartitioner implements Partitioner {
public int partition(String s, Object key, byte[] bytes, Object o1, byte[] bytes1, Cluster cluster) {
if (key.toString().equals("aaa"))
return 0;
else if (key.toString().equals("bbb"))
return 1;
else if (key.toString().equals("ccc"))
return 2;
else return 0;
}
public void close() {
}
public void configure(Map<String, ?> map) {
}
}
测试结果:
partition = 0, offset = 438, key = aaa, value = test32
partition = 1, offset = 448, key = bbb, value = test33
partition = 2, offset = 486, key = ccc, value = test34
partition = 0, offset = 439, key = aaa, value = test35
partition = 1, offset = 449, key = bbb, value = test36
partition = 2, offset = 487, key = ccc, value = test37
partition = 0, offset = 440, key = aaa, value = test38
partition = 1, offset = 450, key = bbb, value = test39
partition = 2, offset = 488, key = ccc, value = test40
partition = 0, offset = 441, key = aaa, value = test41
partition = 1, offset = 451, key = bbb, value = test42
partition = 2, offset = 489, key = ccc, value = test43
partition = 0, offset = 442, key = aaa, value = test44
如果你使用的不是Java的客户端,是javaapi下面的Producer的话,自定义的分区类需要实现kafka.producer.Partitioner,并且有构造函数。
public class TestPartitioner implements Partitioner {
public TestPartitioner (VerifiableProperties props) {
}
public int partition(Object o, int i) {
if (o.toString().equals("aaa"))
return 0;
else if (o.toString().equals("bbb"))
return 1;
else if (o.toString().equals("ccc"))
return 2;
else return 0;
}
}
Kafka学习笔记(二):Partition分发策略的更多相关文章
- 大数据 -- kafka学习笔记:知识点整理(部分转载)
一 为什么需要消息系统 1.解耦 允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束. 2.冗余 消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险.许多 ...
- kafka学习笔记(一)消息队列和kafka入门
概述 学习和使用kafka不知不觉已经将近5年了,觉得应该总结整理一下之前的知识更好,所以决定写一系列kafka学习笔记,在总结的基础上希望自己的知识更上一层楼.写的不对的地方请大家不吝指正,感激万分 ...
- [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计
源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...
- muduo学习笔记(二)Reactor关键结构
目录 muduo学习笔记(二)Reactor关键结构 Reactor简述 什么是Reactor Reactor模型的优缺点 poll简述 poll使用样例 muduo Reactor关键结构 Chan ...
- WPF的Binding学习笔记(二)
原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的 ...
- AJax 学习笔记二(onreadystatechange的作用)
AJax 学习笔记二(onreadystatechange的作用) 当发送一个请求后,客户端无法确定什么时候会完成这个请求,所以需要用事件机制来捕获请求的状态XMLHttpRequest对象提供了on ...
- JMX学习笔记(二)-Notification
Notification通知,也可理解为消息,有通知,必然有发送通知的广播,JMX这里采用了一种订阅的方式,类似于观察者模式,注册一个观察者到广播里,当有通知时,广播通过调用观察者,逐一通知. 这里写 ...
- java之jvm学习笔记二(类装载器的体系结构)
java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...
- Java IO学习笔记二
Java IO学习笔记二 流的概念 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成. 程序中的输入输 ...
- 《SQL必知必会》学习笔记二)
<SQL必知必会>学习笔记(二) 咱们接着上一篇的内容继续.这一篇主要回顾子查询,联合查询,复制表这三类内容. 上一部分基本上都是简单的Select查询,即从单个数据库表中检索数据的单条语 ...
随机推荐
- Ubuntu学习总结-06 安装 Nginx
Nginx是由俄罗斯人(zhan dou min zu)开发的一款高性能的http和反向代理服务器,也可以用来作为邮件代理.相比较于其他的服务器,具有占用内存少,稳定性高等优势. 一 Ubuntu源码 ...
- omnetpp inet
http://blog.csdn.net/midie/article/details/5086983 omnetpp inet 自带了Mingw编译环境,而不再需要Visual C编译环境了.事实上, ...
- aapt aidl
AIDL:Android Interface Definition Language,即Android接口定义语言 aapt即Android Asset Packaging Tool,在SDK的bui ...
- 什么是领域模型(domain model)?贫血模型(anaemic domain model) 和充血模型(rich domain model)有什么区别
http://blog.csdn.net/helloboat/article/details/51208128 领域模型是领域内的概念类或现实世界中对象的可视化表示,又称为概念模型或分析对象模型,它专 ...
- Java中数据类型转换问题
boolean类型不可以转换为替他的数据类型. Java中byte(8位).short(16位).char三种类型的优先级是相同的,相同优先级之间是不能进行自动转换的(如果相互转换的话,必须强制类型转 ...
- PHP高效率写法(详解原因)
1.尽量静态化: 如果一个方法能被静态,那就声明它为静态的,速度可提高1/4,甚至我测试的时候,这个提高了近三倍.当然了,这个测试方法需要在十万级以上次执行,效果才明显.其实静态方法和非静态方法的效率 ...
- python 与 mysql
1.开发环境: 1)CLion-2016.1.3 C/C++ 与 Python 混合编程 IDE,先安装好以下 2) 3) 编译器再关联 2)tdm-gcc-4.8.1-3 C/C++ 编译器 3)W ...
- Linux 解压命令tar的理解
今天回顾了下tar 这个打包工具的一些常用参数 选项与参数: -c :创建打包文件,可搭配 -v 来察看过程中被打包的档名(filename) -t :察看打包文件的内容含有哪些档名,重点在察看『档名 ...
- TYVJ1460 旅行
描述 A国有n座城市,每座城市都十分美,这使得A国的民众们非常喜欢旅行.然而,A国的交通十分落后,这里只有m条双向的道路,并且这些道路都十分崎岖,有的甚至还是山路,只能靠步行.通过每条道路的长度.泥泞 ...
- 《CMake实践》第三部分的示例代码的错误
<CMake实践>的第三章,初试cmake - cmake的helloworld 中的 PROJECT (HELLO) SET(SRC_LIST main.c) MESSAGE(statu ...