本文主要详解kafka client的使用,包括kafka消费者的三种消费语义at-most-once,at-least-once,和exact-once message,生产者的使用等。
创建主题
bin/kafka-topics.sh --zookeeper localhost:2181 --create --topic normal --partitions 2 --rerelication-factor 1
生产者
public class ProducerExample {
public static void main(String[] str) throws InterruptedException, IOException {
System.out.println("Starting ProducerExample ...");
sendMessages();
}
private static void sendMessages() throws InterruptedException, IOException {
Producer<String, String> producer = createProducer();
sendMessages(producer);
// Allow the producer to complete sending of the messages before program exit.
Thread.sleep(20);
}
private static Producer<String, String> createProducer() {
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("acks", "all");
props.put("retries", 0);
// Controls how much bytes sender would wait to batch up before publishing to Kafka.
props.put("batch.size", 10);
props.put("linger.ms", 1);
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
return new KafkaProducer(props);
}
private static void sendMessages(Producer<String, String> producer) {
String topic = "normal-topic";
int partition = 0;
long record = 1;
for (int i = 1; i <= 10; i++) {
producer.send(
new ProducerRecord<String, String>(topic, partition, Long.toString(record),Long.toString(record++)));
}
}
}
消费者
消费者注册到卡夫卡有多种方式:
订阅:这种方式在新增的话题或者分区或者消费者增加或者消费者减少的时候,会进行消费者组内消费者的再平衡。
分配:这种方式注册的消费者不会进行重新平衡。
上面两种方式都是可以实现,三种消费语义的。具体API的使用请看下文。
1.最多一次kafka消费者
最多一次消费语义是kafka消费者的默认实现。配置这种消费者最简单的方式是
1)enable.auto.commit设置为真。
2)auto.commit.interval.ms设置为一个较低的时间范围。
3)consumer.commitSync()不要调用该方法。
由于上面的配置,就可以使得kafka有线程负责按照指定间隔提交偏移。但是这种方式会使得kafka消费者有两种消费语义:
消费语义最多一次 :
消费者的偏移已经提交,但是消息还在处理,这个时候挂了,再重启的时候会从上次提交的偏移处消费,导致上次在处理的消息部分丢失。
消费语义最少一次:
消费者已经处理完了,但是偏移还没提交,那么这个时候消费者挂了,就会导致消费者重复消费消息处理。但是由于auto.commit.interval.ms设置为一个较低的时间范围,会降低这种情况出现的概率。
代码如下:
public class AtMostOnceConsumer {
public static void main(String[] str) throws InterruptedException {
System.out.println("Starting AtMostOnceConsumer ...");
execute();
}
private static void execute() throws InterruptedException {
KafkaConsumer<String, String> consumer = createConsumer();
// Subscribe to all partition in that topic. 'assign' could be used here
// instead of 'subscribe' to subscribe to specif