Kafka笔记三之java操作

本文介绍了如何在Java中使用Kafka,包括配置Maven依赖、设置Kafka与Zookeeper的hosts,以及生产者、消费者和分区器的配置。强调了消费者按分区顺序消费消息和Kafka与Zookeeper的交互,特别是自动提交偏移量的配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

maven依赖,我使用的是版本是0.8.22,scala是2.11

<dependency>

   <groupId>org.apache.kafka</groupId>

   <artifactId>kafka_2.11</artifactId>

   <version>0.8.2.2</version>

</dependency>

 

1.本地测试关闭防火器

2.在windows中配置kafka,zookeeper的host

C:\Windows\System32\drivers\etc\hosts文件

 

生产者

需要将producer.properties文件中的serializer.class参数由DefaultEncoder改为StringEncoder,不然会报错误

serializer.class=kafka.serializer.DefaultEncoder

serializer.class=kafka.serializer.StringEncoder

metadata.broker.list=shb01:9092,129.168.79.139:9092

package kafka;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import kafka.javaapi.producer.Producer;
import kafka.producer.KeyedMessage;
import kafka.producer.ProducerConfig;
/**
 * 生产者实例
 * @author think
 *
 */
public class ProducerTest {

	public static void main(String[] args) throws Exception {

		/**
		 * 属性参数,设置
		 * 方式1:config.setProperty("producer.type", "sync"); 可以手动设置生产者参数
		 * 方式2:直接加载kafka集群中的producer.properties
		 * 在producer.properties中指定broker List
		 * 		metadata.broker.list=shb01:9092,129.168.79.139:9092
		 */
		Properties config = new Properties();
		config.load(ProducerTest.class.getClassLoader().getResourceAsStream("producer.properties"));
		ProducerConfig pConfig = new ProducerConfig(config);
		
		/**
		 * 创建生产者对象
		 * key:为 message的key
		 * value:为message的value
		 */
		Producer<String, String> produce = new Producer<String, String>(pConfig);
		
		/**
		 * 将用户参数组装成message,
		 * KeyedMessage<String, String>:key用来分区,value是消息本身;key可以不写
		 */
		String topic = "hello";
		List<KeyedMessage<String, String>> messageList = new ArrayList<KeyedMessage<String, String>>();
		KeyedMessage<String, String> message1 = new KeyedMessage<String, String>(topic, "key1", "value1");
		KeyedMessage<String, String> message2 = new KeyedMessage<String, String>(topic, "key2", "value2");
		messageList.add(message1);
		messageList.add(message2);
		
		KeyedMessage<String, String> message3 = new KeyedMessage<String, String>(topic, "value3");
		
		/**
		 * 生产者生产消息
		 */
		produce.send(messageList);
		produce.send(message3);
		
		//关闭
		produce.close();
	}
	
}

消费者

消费者是以链接的形式存在,监听生产者生产的消息

zookeeper.connect=shb01:2181,129.168.79.139:2181

group.id=consumer-group-0

package kafka;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import kafka.consumer.Consumer;
import kafka.consumer.ConsumerConfig;
import kafka.consumer.ConsumerIterator;
import kafka.consumer.KafkaStream;
import kafka.javaapi.consumer.ConsumerConnector;
import kafka.message.MessageAndMetadata;


public class ConsumerTest {

	public static void main(String[] args) throws Exception{
		String topic = "hello";
		/**
		 * 属性参数
		 */
		Properties prop = new Properties();
		prop.load(Consumer.class.getClassLoader().getResourceAsStream("consumer.properties"));
		ConsumerConfig conf = new ConsumerConfig(prop);
		
		//创建消费者
		ConsumerConnector createJavaConsumerConnector = Consumer.createJavaConsumerConnector(conf);
		
		//执行消费
		//topicCountMap:key是topic名称,value是该topic所使用的消费者的个数
		Map<String, Integer> topicCountMap = new HashMap<String, Integer>();
		topicCountMap.put(topic, 2);//使用2个消费者消费topic-hello
		/**
		 * messageStreams:
		 * 		key是消费的topic的名称。
		 * 		value是消费者读取 kafka流 
		 */
		Map<String, List<KafkaStream<byte[], byte[]>>> messageStreams = createJavaConsumerConnector.createMessageStreams(topicCountMap);
		//list就是消费者读取的kafka流,有几个消费者就有几个流,此处kafka流的数量为2
		List<KafkaStream<byte[], byte[]>> list = messageStreams.get(topic);
		
		//启动多线程来分别读取
		//KafkaStream<byte[], byte[]>,key是所消费的消息的key,value是所消费的消息value
		for(KafkaStream<byte[], byte[]> kafkaStream : list)
		{
			new Thread(new Worker(kafkaStream)).start();;
		}
	}

	/**
	 * 内部类,用线程接收kafka流
	 * @author think
	 *
	 */
	static class Worker implements Runnable
	{

		private KafkaStream<byte[], byte[]> kafkaStream;
		
		public Worker(KafkaStream<byte[], byte[]> kafkaStream) {
			this.kafkaStream = kafkaStream;
		}

		@Override
		public void run() {
			//使用kafkaStream的迭代器,迭代消费数据
			ConsumerIterator<byte[], byte[]> iterator = kafkaStream.iterator();
			while(iterator.hasNext())
			{
				//MessageAndMetadata就是消息本身
				MessageAndMetadata<byte[], byte[]> next = iterator.next();
				System.out.println(String.format("key:%s  value:%s partition:%s  offset:%s",
						next.key() == null? "": new String(next.key()),
						new String(next.message()),
						next.partition(),
						next.offset()));
			}
		}
		
	}
}

分区器

producer.properties文件

partitioner.class=kafka.ProducerTest

package kafka;

import kafka.producer.Partitioner;
import kafka.utils.VerifiableProperties;
/**
 * 分区器
 * @author think
 * 必须在producer.properties中指定partitioner.class=kafka.ProducerTest
 */
public class PartitionTest implements Partitioner{

	/**
	 * 系统会将生产者的生产属性传递过来供开发者使用,就是producer.properties中的参数值
	 * prop.getProperty("metadata.broker.list");
	 */
	private kafka.utils.VerifiableProperties prop;
	
	/**
	 * 必须提供一个构造方法,参数为VerifiableProperties
	 * @param prop
	 */
	public PartitionTest(VerifiableProperties prop) {
		super();
		this.prop = prop;
	}


	/**
	 * numberPartition:表示partition的数量
	 */
	@Override
	public int partition(Object key, int numberPartition) {
		prop.getProperty("metadata.broker.list");
		//生产者的key是key1,key2
		String keyStr = (String) key;
		if(keyStr.contains("1"))
		{
			return 1;//返回1分区,
		}
		else
		{
			if(keyStr.contains("2"))
			{
				return 2;//返回2分区
			}
		}
		return 0;
	}

}



partition在消费者中的分配

分区会进行排序,消费者会按照其id的字典顺序排序,然后消费者线程数了会除以partition数量,以此来确定每个消费者可以消费的分区数量,如果不能整除则会给第一个消费者多分配一个分区

分区:0 1 2 3 4 5 6 7 8 9

消费者:c1  c2  c3

分配结果:c1 – 0 1 2 3; c2 – 4 5 6;c3 – 7 8 9

 

消费者会按照分区中消息的生产顺序来消费消息,并且是消费完成一个分区后才会去消费另一个分区,所以一个分区中消息的消费是有顺序的而多个分区之间则是无序的。

 

 

Kafka会将一些重要的信息存储在zookeeper中比如broker,consumer,offset等,消费者消费时需要配合zk才可以读取这些信息,但是kafka并不是实时向zookeeper同步信息(默认一分钟),可以在consumer.properties中进行配置auto.commit.enable=true和auto.commit.interval.ms=1000毫秒,通过这两个参数来控制kafka向zk同步的频率。

         Zookeeper支持多个kafka集群,在server.properties中修改参数指定多个kafka集群的目录zookeeper.connect=shb01:2181/demo1,192.168.79.139:2181/demo1,后面在操作topic是注意对应的zk目录。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值