利用java简单调用kafka
来源:互联网 发布:名片设计app软件 编辑:程序博客网 时间:2024/06/04 00:22
我之前的一篇文章简单的介绍了kafka,原理,配置以及搭建,这篇文章主要将利用java使用kafka。
简单的几个名词:
Producer :消息生产者,向broker发消息的客户端。
Consumer :消息消费者,向broker取消息的客户端
Topic :一个队列,主题。
Message:消息是kafka处理的对象,在kafka中,消息是被发布到broker的topic中。而consumer也是从相应的topic中拿数据。也就是说,message是按topic存储的
Consumer Group :将topic消息的广播发给consumer的手段。一个topic可以有多个CG。
Broker :一台kafka服务器就是一个broker。一个集群由多个broker组成。一个broker可以容纳多个topic。
Partition:为了实现扩展性,一个非常大的topic可以分布到多个broker(即服务器)上,一个topic可以分为多个partition,每个partition是一个有序的队列。partition中的每条消息都会被分配一个有序的id(offset)。kafka只保证按一个partition中的顺序将消息发给consumer,不保证一个topic的整体(多个partition间)的顺序。
Offset:kafka的存储文件都是按照offset.kafka来命名,用offset做名字的好处是方便查找。例如你想找位于2049的位置,只要找到2048.kafka的文件即可。当然the first offset就是00000000000.kafka
java调用kafka
首先创建一个java project,有的博客说maven和普通的java project均可调用,我没尝试普通的java project,我使用的是maven工程。
需要注意,工程所采用的jar包,可以在相应版本的kafka安装文件夹的lib目录下引用,不同版本的jar包可能不通用,
如果出现java.lang.NoClassDefFoundError: scala/reflect/ClassManifest的报错,可能是由于jar包不匹配引起的。
Producer端代码:
import java.util.Date;import java.util.Properties;import java.text.SimpleDateFormat; import kafka.javaapi.producer.Producer;import kafka.producer.KeyedMessage;import kafka.producer.ProducerConfig;public class Producertest { public static void main(String[] args) { Properties props = new Properties(); props.put("zk.connect", "hadoop1:2181/kafka,hadoop2:2181/kafka,hadoop3:2181/kafka,hadoop4:2181/kafka,hadoop5:2181/kafka,hadoop6:2181/kafka"); // serializer.class为消息的序列化类 props.put("serializer.class", "kafka.serializer.StringEncoder"); // 配置metadata.broker.list, 为了高可用, 最好配两个broker实例 props.put("metadata.broker.list", "hadoop1:9092,hadoop2:9092,hadoop3:9092"); // 设置Partition类, 对队列进行合理的划分 //props.put("partitioner.class", "idoall.testkafka.Partitionertest"); // ACK机制, 消息发送需要kafka服务端确认 props.put("request.required.acks", "1"); props.put("num.partitions", "6"); ProducerConfig config = new ProducerConfig(props); Producer<String, String> producer = new Producer<String, String>(config); for (int i = 0; i < 10; i++) { // KeyedMessage<K, V> // K对应Partition Key的类型 // V对应消息本身的类型// topic: "test", key: "key", message: "message" SimpleDateFormat formatter = new SimpleDateFormat ("yyyy年MM月dd日 HH:mm:ss SSS"); Date curDate = new Date(System.currentTimeMillis());//获取当前时间 String str = formatter.format(curDate); String msg = "idoall.org" + i+"="+str; String key = i+""; producer.send(new KeyedMessage<String, String>("idoall_testTopic",key, msg)); } }}
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;public class Consumertest extends Thread{ private final ConsumerConnector consumer; private final String topic; public static void main(String[] args) { Consumertest consumerThread = new Consumertest("idoall_testTopic"); consumerThread.start(); } public Consumertest(String topic) { consumer =kafka.consumer.Consumer.createJavaConsumerConnector(createConsumerConfig()); this.topic =topic; } private static ConsumerConfig createConsumerConfig() { Properties props = new Properties(); // 设置zookeeper的链接地址 props.put("zookeeper.connect","hadoop1,hadoop2,hadoop3,hadoop4,hadoop5,hadoop6:2181"); // 设置group id props.put("group.id", "1"); // kafka的group 消费记录是保存在zookeeper上的, 但这个信息在zookeeper上不是实时更新的, 需要有个间隔时间更新 props.put("auto.commit.interval.ms", "1000"); props.put("zookeeper.session.timeout.ms","10000"); return new ConsumerConfig(props); } public void run(){ //设置Topic=>Thread Num映射关系, 构建具体的流 Map<String,Integer> topickMap = new HashMap<String, Integer>(); topickMap.put(topic, 1); Map<String, List<KafkaStream<byte[],byte[]>>> streamMap=consumer.createMessageStreams(topickMap); KafkaStream<byte[],byte[]>stream = streamMap.get(topic).get(0); ConsumerIterator<byte[],byte[]> it =stream.iterator(); System.out.println("*********Results********"); while(it.hasNext()){ System.err.println("get data:" +new String(it.next().message())); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
之后运行代码即可。
运行Producer端代码,会发现之前的客户端中会接收到代码中发送的消息。
运行consumer端代码,在终端中输入消息,eclipse中会读取到发送的消息,打印出来。
至此,简单的java调用kafka操作完成。
附:
如果将Kafka在zookeeper的默认目录,修改为自定义目录时,在运行过程中会报出java.lang.IllegalArgumentException: Path length must be > 0”错误
网上找了好久,发现别人说这是一个Bug,由于initZk()方法没有对路径进行处理导致
原代码:
private def initZk(): ZkClient = {
info(“Connecting to zookeeper on ” + config.zkConnect)
val zkClient = new ZkClient(config.zkConnect, config.zkSessionTimeoutMs, config.zkConnectionTimeoutMs, ZKStringSerializer)
ZkUtils.setupCommonPaths(zkClient)
zkClient
}
解决代码:
private def initZk(): ZkClient = {
info(“Connecting to zookeeper on ” + config.zkConnect)
val chroot = {
if (config.zkConnect.indexOf(“/”) > 0)
config.zkConnect.substring(config.zkConnect.indexOf(“/”))
else
“”
}
if (chroot.length > 1) {
val zkConnForChrootCreation = config.zkConnect.substring(0, config.zkConnect.indexOf(“/”))
val zkClientForChrootCreation = new ZkClient(zkConnForChrootCreation, config.zkSessionTimeoutMs, config.zkConnectionTimeoutMs, ZKStringSerializer)
ZkUtils.makeSurePersistentPathExists(zkClientForChrootCreation, chroot)
info(“Created zookeeper path ” + chroot)
zkClientForChrootCreation.close()
}
val zkClient = new ZkClient(config.zkConnect, config.zkSessionTimeoutMs, config.zkConnectionTimeoutMs, ZKStringSerializer)
ZkUtils.setupCommonPaths(zkClient)
zkClient
}
如果无法修改,那么可以将自定义目录修改成原来的默认目录,则不会报错。
- 利用java简单调用kafka
- kafka介绍,安装以及简单的java调用kafka代码
- Java 调用Kafka
- kafka java简单例子
- java调用Kafka的Consumer
- kafka java客户端调用问题
- 利用Kafka发送/消费消息-Java示例
- Kafka学习笔记-Java简单操作
- java客户端连接kafka简单测试
- Java线程简单调用
- 利用Java调用可执行命令
- 利用Java调用可执行命令
- 利用Java调用可执行命令
- 利用Java调用可执行命令
- 利用Java调用可执行命令
- 利用Java调用可执行命令
- 利用中断调用实现简单的输入输出
- 利用中断调用实现简单的输入输出
- jstl标签中的循环 s:bean
- 第十五章 课后作业4题
- Java加密算法---HMAC
- IEC61850笔记--IEC61850应用入门(二)
- 配置获取隐私数据权限声明
- 利用java简单调用kafka
- android中shape详解
- Hive总结(十)Hive 输入输出适配类(输出CSV,XML)
- 10053 事件详解
- docker配置默认创建mysql 数据库的编码
- iOS socket编程
- MongoDB shell命令
- mysql 常用函数
- Android动态高斯模糊效果教程