kafka06-开发应用生产者和消费者
版本信息kafka 1.0.2
1生产者
生产者主要的对象有: KafkaProducer , ProducerRecord 。
其中 KafkaProducer 是用于发送消息的类, ProducerRecord 类用于封装Kafka的消息。
KafkaProducer 的创建需要指定的参数和含义:
参数 | 说明 |
---|---|
bootstrap.servers | 配置生产者如何与broker建立连接。该参数设置的是初始化参数。如果生 |
key.serializer | 要发送信息的key数据的序列化类。设置的时候可以写类名,也可以使用该类的Class对象。 |
value.serializer | 要发送消息的alue数据的序列化类。设置的时候可以写类名,也可以使用该类的Class对象。 |
acks | 默认值:all。 acks=0: 生产者不等待broker对消息的确认,只要将消息放到缓冲区,就认为消息 已经发送完成。 该情形不能保证broker是否真的收到了消息,retries配置也不会生效。发 送的消息的返回的消息偏移量永远是-1。 acks=1 表示消息只需要写到主分区即可,然后就响应客户端,而不等待副本分区 的确认。 在该情形下,如果主分区收到消息确认之后就宕机了,而副本分区还没来 得及同步该消息,则该消息丢失。 acks=all 首领分区会等待所有的ISR副本分区确认记录。 该处理保证了只要有一个ISR副本分区存活,消息就不会丢失。 这是Kafka最强的可靠性保证,等效于 acks=-1 |
retries | retries重试次数 当消息发送出现错误的时候,系统会重发消息。 跟客户端收到错误时重发一样。 如果设置了重试,还想保证消息的有序性,需要设置 MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION=1 否则在重试此失败消息的时候,其他的消息可能发送成功了 |
其他参数可以从 org.apache.kafka.clients.producer.ProducerConfig 中找到
消费者生产消息后,需要broker端的确认,可以同步确认,也可以异步确认。
同步确认效率低,异步确认效率高,但是需要设置回调对象。
package com.lew.demo;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.apache.kafka.common.header.Header;
import org.apache.kafka.common.header.internals.RecordHeader;
import org.apache.kafka.common.serialization.IntegerSerializer;
import org.apache.kafka.common.serialization.StringSerializer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
/**
* @Author llewcg
* @Description
*/
public class ProducerTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Map<String, Object> configs = new HashMap<>();
// 设置连接Kafka的初始连接用到的服务器地址
// 如果是集群,则可以通过此初始连接发现集群中的其他broker 一般设置2-3个即可
configs.put("bootstrap.servers", "10.10.1.135:9092");
// 设置key的序列化器
configs.put("key.serializer", IntegerSerializer.class);
// 设置value的序列化器
configs.put("value.serializer", StringSerializer.class);
KafkaProducer<Integer, String> producer = new KafkaProducer<>(configs);
//设置自定义消息头
List<Header> header = new ArrayList<>();
header.add(new RecordHeader("biz.name", "producer".getBytes()));
ProducerRecord<Integer, String> record = new ProducerRecord<Integer, String>(
"gc_test1",
0,
11,
"gcWell llewgc",
header
);
//消息的同步确认等待
Future<RecordMetadata> future = producer.send(record);
RecordMetadata recordMetadata = future.get();
System.out.println("主题:" + recordMetadata.topic());
System.out.println("分区:" + recordMetadata.partition());
System.out.println("偏移量:" + recordMetadata.hasOffset());
//关闭生产者
producer.close();
}
}
消费者
[root@lew1 ~]# kafka-console-consumer.sh --bootstrap-server lew1:9092 --topic gc_test1
gcWell llewgc
pom
<dependencies>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>1.0.2</version>
</dependency>
</dependencies>
2消费者
参数 | 说明 |
---|---|
bootstrap.servers | 与kafka建立连接的broker地址列表 |
key.deserializer | key的反序列化器 |
value.deserializer | value的反序列化器 |
group.id | 消费组id,标识消费者所属消费组 |
auto.offset.reset | 当kafka没有初始偏移量或偏移量不存在时 earliest:自动重置偏移量到最早的偏移量 lastest:到最新的偏移量 none:如果消费组原来偏移量不存在,向消费组抛出异常 nothing:向消费组抛出异常 |
package com.lew.demo.consumer;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.serialization.IntegerDeserializer;
import org.apache.kafka.common.serialization.StringDeserializer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* @Author llewcg
* @Description
*/
public class ConsumerTest {
public static void main(String[] args) {
Map<String, Object> config = new HashMap<>();
config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "lew1:9092");
//key的反序列化器
config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, IntegerDeserializer.class);
//value的反序列化器
config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
//消费组
config.put(ConsumerConfig.GROUP_ID_CONFIG, "group_gc1");
//找不到当前消费者的有效偏移量,则从最早的偏移量开始消费
config.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
KafkaConsumer<Integer, String> consumer = new KafkaConsumer<>(config);
consumer.subscribe(Arrays.asList("gc_test1"));
while (true) {
//批量从主题拉取数据
//主题中没有可供拉取的消息时,没过3s拉取一次数据
ConsumerRecords<Integer, String> consumerRecords = consumer.poll(3000);
consumerRecords.forEach(x -> {
System.out.println(x.topic() + "\t" +
x.partition() + "\t" +
x.offset() + "\t" +
x.key() + "\t" +
x.value());
});
}
}
}