Java使用Producer向Kafka集群发送消息

本文详细介绍了Java使用KafkaProducerAPI向Kafka集群发送消息的三种方式:直接发送、同步发送和异步发送。在直接发送中,消息可能会丢失但适合日志记录;同步发送会等待Kafka确认,确保消息发送成功;异步发送结合回调处理,可在发送后执行其他操作。每种方式都涉及到消息序列化、异常处理和发送策略。
摘要由CSDN通过智能技术生成

Java使用Kafka Producer API向Kafka集群发送消息的时候,大概有3中形式,分别为直接、同步、异步发送,本篇文章会介绍这3中发布方式的区别

一、Pom文件配置

<dependency>
	<groupId>org.apache.kafka</groupId>
	<artifactId>kafka-clients</artifactId>
	<version>0.9.0.1</version>
</dependency>

二、向Kafka集群发送消息

2.1 直接发送

import java.util.Properties;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;

public class Producer1 {

	public static void main(String[] args) {

		Properties kafkaProps = new Properties();
		kafkaProps.put("bootstrap.servers", "10.202.62.66:9092,10.202.62.67:9092,10.202.62.68:9092");
		kafkaProps.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
		kafkaProps.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
		KafkaProducer<String, String> producer = new KafkaProducer<String, String>(kafkaProps);
		// 直接发送
		for (int i = 0; i < 100; i++) {
			ProducerRecord<String, String> record = new ProducerRecord<>("testtopic", "key" + i, "message " + i);
			producer.send(record);

		}
		producer.flush();
		producer.close();
	}
}

这里有几个注意事项:

(1) Producer接收是ProducerRecord对象,因此最开始的时候需要创建ProducerRecord的对象。ProducerRecord有好几种构造方法,稍后我们会讲到。上面例子中需要填写接收消息的topic(以啊不能都是字符串类型),想要发送的key和value。key和value的类型必须要和序列化保持一致。

(2) 使用send()方法发送ProducerRecord对象,就像最开始Kafka的架构一样,消息会先缓存在buffer,然后开启独立的线程发送给broker。send()方法返回一个Java Future对象,对象中包含RecordMetadata,在上面的例子中并没有关心返回值,因此也就不知道消息是否发送成功,这种一般适用于允许丢失消息的情况。比如记录一些日志信息或者是不太重要的应用信息。

(3) 虽然我们忽略了向broker发送数据时出的错或者是Broker自己出的错,在producer发送数据前如果有错误仍然会抛出异常。有可能是在序列化消息的时候,产生了异常。比如说Buffer已经满了或者是发送线程中断产生的中断异常。

2.2 同步发送

import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;

public class Producer2 {

	public static void main(String[] args) {

		Properties kafkaProps = new Properties();
		kafkaProps.put("bootstrap.servers", "10.202.62.66:9092,10.202.62.67:9092,10.202.62.68:9092");
		kafkaProps.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
		kafkaProps.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
		KafkaProducer<String, String> producer = new KafkaProducer<String, String>(kafkaProps);

		// 同步发送
		for (int i = 0; i < 100; i++) {
			ProducerRecord<String, String> record = new ProducerRecord<>("testtopic", "key-"+i, "message " + i);
			Future<RecordMetadata> result = producer.send(record);
			try {
				RecordMetadata m = result.get();
				System.out.println("partition:" + m.partition() + ",offset:" + m.offset());
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
		}
		producer.flush();
		producer.close();

	}
}

(1)这里用了Future.get()方法,会等待kafka的确认回复。当broker遇到错误或者应用出现问题时,future接口都会抛出异常,然后我们可以捕获到这个异常进行处理。如果没有错误。将会获得RecordMetadata对象,这个对象包含了消息写入的偏移值。

(2)Producer有两种错误类型。一种是可以通过再次发送消息解决的错误,比如连接出现问题,需要重新连接;或者是"no leader"错误,通过等待一会Leader重新选举完就可以继续。producer可以配置自动重试。另一种是通过重试无法处理的错误,比如消息过大,这种情况下,Producer就不会重试,而是直接抛出异常。

2.3 异步发送

import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.apache.kafka.clients.producer.Callback;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;

public class Producer3 {

	public static void main(String[] args) {
		Properties kafkaProps = new Properties();

		kafkaProps.put("bootstrap.servers", "10.202.62.66:9092,10.202.62.67:9092,10.202.62.68:9092");
		kafkaProps.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
		kafkaProps.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
		KafkaProducer<String, String> producer = new KafkaProducer<String, String>(kafkaProps);

		for (int i = 0; i < 100; i++) {
			ProducerRecord<String, String> record = new ProducerRecord<>("testtopic", "key" + i, "async message " + i);
			Future<RecordMetadata> result = producer.send(record, new Callback() {
				@Override
				public void onCompletion(RecordMetadata metadata, Exception exception) {
					if (exception != null) {
						exception.printStackTrace();
					}
					if (metadata != null) {
						System.out.println("partition:" + metadata.partition() + ",offset:" + metadata.offset());
					}
				}
			});

			try {
				RecordMetadata m = result.get();
				System.out.println(m.partition() + "," + m.topic());
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		producer.flush();
		producer.close();
	}
}

(1) 为了使用回调方法,需要实现org.apache.kafka.clients.producer.Callback接口,实现它的onCompletion方法。

(2) 当Kafka返回错误的时候,onCompletion方法会收到一个非null的异常。上面的例子直接打印异常消息,但是如果是生产环境,需要做一些处理错误的操作。

(3) 记录的创建和之前是一样的

(4)需要再发送消息的时候,传入回调的对象

2.4 Flume使用的发送方式

package com.master.kafka;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.apache.kafka.clients.producer.Callback;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;

public class FlumeProducer {

	public static void main(String[] args) {
		Properties kafkaProps = new Properties();
		List<Future<RecordMetadata>> list = new ArrayList<Future<RecordMetadata>>();
		kafkaProps.put("bootstrap.servers", "10.202.62.66:9092,10.202.62.67:9092,10.202.62.68:9092");
		kafkaProps.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
		kafkaProps.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
		KafkaProducer<String, String> producer = new KafkaProducer<String, String>(kafkaProps);
		for (int i = 0; i < 100; i++) {
			ProducerRecord<String, String> record = new ProducerRecord<>("testtopic", "key--" + i,
					"flume message " + i);
			Future<RecordMetadata> result = producer.send(record, new Callback() {
				@Override
				public void onCompletion(RecordMetadata metadata, Exception exception) {
					if (exception != null) {
						exception.printStackTrace();
					}
					if (metadata != null) {
						System.out.println("partition:" + metadata.partition() + ",offset:" + metadata.offset());
					}
				}
			});
			list.add(result);
		}
		for (Future<RecordMetadata> future : list) {
			try {
				future.get();
			} catch (InterruptedException | ExecutionException e) {
				e.printStackTrace();
			}
		}
		producer.flush();
		producer.close();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值