Kafka笔记三之java操作

来源:互联网 发布:淘宝手机端怎么排名 编辑:程序博客网 时间:2024/06/06 01:02

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流的数量为2List<KafkaStream<byte[], byte[]>> list = messageStreams.get(topic);//启动多线程来分别读取//KafkaStream<byte[], byte[]>,key是所消费的消息的key,value是所消费的消息valuefor(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;}@Overridepublic 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的数量 */@Overridepublic int partition(Object key, int numberPartition) {prop.getProperty("metadata.broker.list");//生产者的key是key1,key2String 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目录。



0 0
原创粉丝点击