Kafka笔记--指定消息的partition规则
参数的设定:参考资料
不错的资料:http://blog.csdn.net/honglei915/article/details/37697655
http://developer.51cto.com/art/201501/464491.htm
注意:在配置文件server.properties中指定了partition的数量num.partitions。这指的是多单个topic的partition数量之和。若有多个broker,可能partition分布在不同的节点上,则多个broker的所有partitioin数量加起来为num.partitions
0.7中producer的配置有几项是相排斥的,设置了其一,就不能设置其二
比如:
broker.list 与 zk.connect 不能同时设置
broker.list 与 partitioner.class 不能同时设置
如果这么干,编译时无所谓,运行时会抛异常
1,指定broker
props.put("broker.list", "0:10.10.10.10:9092");//直接连接kafka
设置这项后,就不能设置partitioner.class了,可是我在运行的时候发现,此时所有的数据都发往10.10.10.10的4个分区,并没有只发给一个分区。我换了syncproducer里的send(topic,partitionid,list)都没用。
2,指定partition
props.put("partitioner.class","com.kafka.myparitioner.CidPartitioner");
props.put("zk.connect", "10.10.10.10:2181");//连接zk
上面的 com.kafka.myparitioner.CidPartitioner 为自己实现的类,注意要自己实现完整的包名
CidPartitioner继承了Partitioner类,其中实现的partition方法指定了通过key计算partition的方法
package com.kafka.myparitioner; import kafka.producer.Partitioner;
import kafka.utils.VerifiableProperties; //设定依据key将当前这条消息发送到哪个partition的规则
public class CidPartitioner implements Partitioner {
public CidPartitioner(VerifiableProperties props) {
//注意 : 构造函数的函数体没有东西,但是不能没有构造函数
} @Override
public int partition(Object key, int numPartitions) {
try {
long partitionNum = Long.parseLong((String) key);
return (int) Math.abs(partitionNum % numPartitions);
} catch (Exception e) {
return Math.abs(key.hashCode() % numPartitions);
}
}
}
想要依据key来进行partition的分配,需要在发送消息的时候指定key。
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;
import java.util.regex.Pattern; import kafka.producer.KeyedMessage;
import kafka.producer.ProducerConfig; //与KafkaReceiverLTELogSocket的区别在于,指定了消息的partition分配规则
public class KafkaReceiveLTELogSocketPartition extends Thread{
//按照一定的时间间隔发送LTE信令数据
String regEx ="[^0-9.\\+\\-\\s+\\,E]";
Pattern p = Pattern.compile(regEx); //第一个类型代表key的类型,第二个代表消息的类型
private final kafka.javaapi.producer.Producer<String, String> producer;
private final String topic;
private final Properties props = new Properties(); private final int port = 12345; public KafkaReceiveLTELogSocketPartition(String topic) {
props.put("serializer.class", "kafka.serializer.StringEncoder");
props.put("metadata.broker.list", "192.168.1.164:9093"); // 配置kafka端口
props.put("partitioner.class","com.kafka.myparitioner.CidPartitioner");
//props.put("zk.connect", "192.168.1.164:2181");//连接zk,新的版本好像不需要 producer = new kafka.javaapi.producer.Producer<String, String>(new ProducerConfig(props));
this.topic = topic;
} public void receiveAndWrite2(String outputFileName , int port) throws IOException{
ServerSocket serverSocket = new ServerSocket(port);
Socket socket = serverSocket.accept();
StringBuilder sb = new StringBuilder();
try{
while(true){
InputStream istream = socket.getInputStream();
int count = 0;
while (count == 0) {
count = istream.available();
}
byte[] b = new byte[count];
istream.read(b);
for(int i = 0 ; i < count ; i ++){
if(b[i]=='\n'){ //当遇到流中的换行符时,说明已经获取一条完整的信息,发送
String str = sb.toString(); //获取key_cid_str
String key_cid_str = str.substring(str.indexOf(":")+1, str.indexOf(",")); System.out.println("接收长度:"+str.length());
System.out.println(str);
//第一个参数代表key的类型,第二个参数代表message的类型
producer.send(new KeyedMessage<String, String>(topic,key_cid_str,str)); sb = new StringBuilder();
}else{
sb.append(Character.toChars(b[i]));
}
}
} }finally{
// 关闭socket,不要再while中关闭,否则发送方每次都要重建连接
socket.close();
serverSocket.close();
}
} @Override
public void run() {
String filename = "JSON1_Yanming_DriveTesting_09-04.16-17.16-27_TIME.json";
String outputFileName = ""+filename; try {
receiveAndWrite2(outputFileName,port);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String topic = "kafka_flume_topic";
new KafkaReceiveLTELogSocketPartition(topic).start();
}
}
利用KafkaConsumer输出(这里使用高级别Consumer)
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties; import kafka.consumer.ConsumerConfig;
import kafka.consumer.ConsumerIterator;
import kafka.consumer.KafkaStream;
import kafka.javaapi.consumer.ConsumerConnector;
import kafka.message.MessageAndMetadata; public class KafkaConsumer extends Thread {
private final ConsumerConnector consumer;
private final String topic; public KafkaConsumer(String topic) {
consumer = kafka.consumer.Consumer.createJavaConsumerConnector(createConsumerConfig());
this.topic = topic;
} private static ConsumerConfig createConsumerConfig() {
Properties props = new Properties();
props.put("zookeeper.connect", "192.168.1.164:2181"); // zookeeper的地址
props.put("group.id", "group2"); // 组ID //zk连接超时
props.put("zookeeper.session.timeout.ms", "40000");
props.put("zookeeper.sync.time.ms", "200");
props.put("auto.commit.interval.ms", "1000"); return new ConsumerConfig(props);
} @Override
public void run() {
Map<String, Integer> topicCountMap = new HashMap<String, Integer>();
//设定每个topic开几个线程
topicCountMap.put(topic, new Integer(1)); Map<String, List<KafkaStream<byte[], byte[]>>> consumerMap = consumer.createMessageStreams(topicCountMap); KafkaStream<byte[], byte[]> stream = consumerMap.get(topic).get(0);
ConsumerIterator<byte[], byte[]> it = stream.iterator();
while (it.hasNext()) {
MessageAndMetadata<byte[], byte[]> message = it.next();
String topic = message.topic();
int partition = message.partition();
long offset = message.offset();
String key = new String(message.key());
String msg = new String(message.message());
// 在这里处理消息,这里仅简单的输出
// 如果消息消费失败,可以将已上信息打印到日志中,活着发送到报警短信和邮件中,以便后续处理
System.out.println( " thread : " + Thread.currentThread().getName()
+ ", topic : " + topic + ", partition : " + partition + ", offset : " + offset + " , key : "
+ key + " , mess : " + msg);
}
}
}
附加:Kafka低级别consumer
package com.cuicui.kafkademon; import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import kafka.api.FetchRequest;
import kafka.api.FetchRequestBuilder;
import kafka.api.PartitionOffsetRequestInfo;
import kafka.cluster.Broker;
import kafka.common.TopicAndPartition;
import kafka.javaapi.FetchResponse;
import kafka.javaapi.OffsetRequest;
import kafka.javaapi.OffsetResponse;
import kafka.javaapi.PartitionMetadata;
import kafka.javaapi.TopicMetadata;
import kafka.javaapi.TopicMetadataRequest;
import kafka.javaapi.TopicMetadataResponse;
import kafka.javaapi.consumer.SimpleConsumer;
import kafka.javaapi.message.ByteBufferMessageSet;
import kafka.message.Message;
import kafka.message.MessageAndOffset; /**
* offset自己维护 目标topic、partition均由自己分配
*
* @author <a href="mailto:leicui001@126.com">崔磊</a>
* @date 2015年11月4日 上午11:44:15
*
*/
public class MySimpleConsumer { public static void main(String[] args) {
new MySimpleConsumer().consume();
} /**
* 消费消息
*/
public void consume() {
int partition = 0; // 找到leader
Broker leaderBroker = findLeader(KafkaProperties.BROKER_CONNECT, KafkaProperties.TOPIC, partition); // 从leader消费
SimpleConsumer simpleConsumer =
new SimpleConsumer(leaderBroker.host(), leaderBroker.port(), 20000, 10000, "mySimpleConsumer");
long startOffet = 1;
int fetchSize = 1000; while (true) {
long offset = startOffet;
// 添加fetch指定目标tipic,分区,起始offset及fetchSize(字节),可以添加多个fetch
FetchRequest req =
new FetchRequestBuilder().addFetch(KafkaProperties.TOPIC, 0, startOffet, fetchSize).build(); // 拉取消息
FetchResponse fetchResponse = simpleConsumer.fetch(req); ByteBufferMessageSet messageSet = fetchResponse.messageSet(KafkaProperties.TOPIC, partition);
for (MessageAndOffset messageAndOffset : messageSet) {
Message mess = messageAndOffset.message();
ByteBuffer payload = mess.payload();
byte[] bytes = new byte[payload.limit()];
payload.get(bytes);
String msg = new String(bytes); offset = messageAndOffset.offset();
System.out.println("partition : " + 3 + ", offset : " + offset + " mess : " + msg);
}
// 继续消费下一批
startOffet = offset + 1;
}
} /**
* 找到制定分区的leader broker
*
* @param brokerHosts broker地址,格式为:“host1:port1,host2:port2,host3:port3”
* @param topic topic
* @param partition 分区
* @return
*/
public Broker findLeader(String brokerHosts, String topic, int partition) {
Broker leader = findPartitionMetadata(brokerHosts, topic, partition).leader();
System.out.println(String.format("Leader tor topic %s, partition %d is %s:%d", topic, partition, leader.host(),
leader.port()));
return leader;
} /**
* 找到指定分区的元数据
*
* @param brokerHosts broker地址,格式为:“host1:port1,host2:port2,host3:port3”
* @param topic topic
* @param partition 分区
* @return 元数据
*/
private PartitionMetadata findPartitionMetadata(String brokerHosts, String topic, int partition) {
PartitionMetadata returnMetaData = null;
for (String brokerHost : brokerHosts.split(",")) {
SimpleConsumer consumer = null;
String[] splits = brokerHost.split(":");
consumer = new SimpleConsumer(splits[0], Integer.valueOf(splits[1]), 100000, 64 * 1024, "leaderLookup");
List<String> topics = Collections.singletonList(topic);
TopicMetadataRequest request = new TopicMetadataRequest(topics);
TopicMetadataResponse response = consumer.send(request);
List<TopicMetadata> topicMetadatas = response.topicsMetadata();
for (TopicMetadata topicMetadata : topicMetadatas) {
for (PartitionMetadata PartitionMetadata : topicMetadata.partitionsMetadata()) {
if (PartitionMetadata.partitionId() == partition) {
returnMetaData = PartitionMetadata;
}
}
}
if (consumer != null)
consumer.close();
}
return returnMetaData;
} /**
* 根据时间戳找到某个客户端消费的offset
*
* @param consumer SimpleConsumer
* @param topic topic
* @param partition 分区
* @param clientID 客户端的ID
* @param whichTime 时间戳
* @return offset
*/
public long getLastOffset(SimpleConsumer consumer, String topic, int partition, String clientID, long whichTime) {
TopicAndPartition topicAndPartition = new TopicAndPartition(topic, partition);
Map<TopicAndPartition, PartitionOffsetRequestInfo> requestInfo =
new HashMap<TopicAndPartition, PartitionOffsetRequestInfo>();
requestInfo.put(topicAndPartition, new PartitionOffsetRequestInfo(whichTime, 1));
OffsetRequest request = new OffsetRequest(requestInfo, kafka.api.OffsetRequest.CurrentVersion(), clientID);
OffsetResponse response = consumer.getOffsetsBefore(request);
long[] offsets = response.offsets(topic, partition);
return offsets[0];
}
}
Kafka笔记--指定消息的partition规则的更多相关文章
- kafka topic消息分配partition规则(Java源码)
我们知道Kafka 的消息通过topic进行分类.topic可以被分为若干个partition来存储消息.消息以追加的方式写入partition,然后以先入先出的顺序读取. 下面是topic和part ...
- Kafka文件存储机制及partition和offset
转载自: https://yq.aliyun.com/ziliao/65771 参考: Kafka集群partition replication默认自动分配分析 如何为kafka选择合适的p ...
- Kafka(2)--kafka基本原理之消息的分发与接收
关于 Topic 和 Partition Topic 在 kafka 中,topic 是一个存储消息的逻辑概念,可以认为是一个消息集合.每条消息发送到 kafka 集群的消息都有一个类别.物理上来说, ...
- Kafka笔记整理(一)
Kafka简介 消息队列(Message Queue) 消息 Message 网络中的两台计算机或者两个通讯设备之间传递的数据.例如说:文本.音乐.视频等内容. 队列 Queue 一种特殊的线性表(数 ...
- Kafka笔记整理(三):消费形式验证与性能测试
Kafka消费形式验证 前面的<Kafka笔记整理(一)>中有提到消费者的消费形式,说明如下: .每个consumer属于一个consumer group,可以指定组id.group.id ...
- Kafka作为分布式消息系统的系统解析
Kafka概述 Apache Kafka由Scala和Java编写,基于生产者和消费者模型作为开源的分布式发布订阅消息系统.它提供了类似于JMS的特性,但设计上又有很大区别,它不是JMS规范的实现,如 ...
- Kafka笔记1(初步认识)
Kafka 被称为“分布式提交日志”或“分布式流平台” 文件系统或数据库提交日志用来提供所有事务的持久记录,通过重放这些日志重建系统状态,同时Kafka数据是按照一定顺序持久化保存的,可以按需读取 K ...
- Kafka笔记7
Kafka提供了一些命令行工具,用于管理集群变更.这些工具使用Java实现,Kafka提供了一些脚本调用这些Java类. 9.1主题操作 使用Kafka-topics.sh工具可以执行主题大部分工作, ...
- Kafka笔记5
Kafka使用zookeeper来维护集群成员的信息.每个broker都有一个唯一标识符,这个标识符可以在配置文件指定,也可以自动生成. 在broker停机,出现网络分区或者长时间垃圾回收停顿时,br ...
随机推荐
- Qt Quick 事件处理之信号与槽
前面两篇文章<QML 语言基础>和<Qt Quick 简单教程>中我们介绍了 QML 语言的基本的语法和 Qt Quick 的常见元素,亲们,通过这两篇文章,您应该已经能够完毕 ...
- cocos2d_android开发简单游戏
1)游戏图层设计: public class WellcomeLayer extends CCLayer { public WellcomeLayer() { this.setIsTouchEnabl ...
- SimpleDateFormat使用简析
title: SimpleDateFormat使用简析 date: 2016-07-11 11:48:20 tags: Java SimpleDateFormat --- [转载自博客:http:// ...
- Observer 观察者模式
简介 观察者模式(Observer),有时又被称为[发布]publish-[订阅]Subscribe模式.模型-视图(View)模式.源-收听者(Listener)模式或从属者模式.在此种 ...
- 修改DeDe标签Pagelist分页样式
我们在用dede仿站的时候,调用文章列表页的分页时,我们会用到: {dede:pagelist listitem=”info,index,end,pre,next,pageno” listsize=” ...
- c-函数指针(求奇数偶数的和)
#include <stdio.h> /* 编写一个函数,输入 n 为偶数时,调用函数求 1/2+1/4+...+1/n,当输入 n 为奇数时,调用函数1/1+1/3+...+1/n(利用 ...
- 99%Bug 修复方法
以下仅支持4.0.3或之后的设备 (写在前面,这个教程需要安装两个app,且卸载后无法达到效果,所以有app drawer洁癖者慎重(你可以把它们隐藏起来么). 当然等官方rom更新或者安装最新三方r ...
- iOS9中将图片保存到照片中的某个相册的方法说明
iOS9中将图片保存到照片中的某个相册的方法说明 在App中很经常遇到的就是用户点击某张图片后将图片保存到本地,下面介绍下iOS中保存图片的一些东西 1.首先,在iOS中把图片保存到系统照片是比较简单 ...
- IOS改变状态栏样式
1.状态栏高亮颜色 在info.plist中添加 View controller-based status bar appearance 设置为 "NO"在AppDelegate. ...
- JavaScript--数组--sort比较器
因为原装的sort这个API其实是先把要比较的数转换为字符串再进行比较的,所以并不好用 所以准备自定义一个比较器函数: //sort原理--->sort(arr,compare) functio ...