原文地址:https://kafka.apache.org/30/javadoc/org/apache/kafka/clients/producer/KafkaProducer.html
公共类KafkaProducer
extends Object
实现了Producer
将记录发布到 Kafka 集群的 Kafka 客户端。
生产者是线程安全的,跨线程共享单个生产者实例通常比拥有多个实例更快。
下面是一个简单的例子,它使用生产者发送包含序列号作为键/值对的字符串的记录。
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("acks", "all");
props.put("retries", 0);
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");
Producer<String, String> producer = new KafkaProducer<>(props);
for (int i = 0; i < 100; i++)
producer.send(new ProducerRecord<String, String>("my-topic", Integer.toString(i), Integer.toString(i)));
producer.close();
生产者由一个缓冲空间池和一个后台 I/O 线程组成,该池保存尚未传输到服务器的记录,以及负责将这些记录转换为请求并将它们传输到集群的后台 I/O 线程。使用后不关闭生产者会泄露这些资源。
该send()方法是异步的。当被调用时,它将记录添加到待发送记录的缓冲区中并立即返回。这允许生产者将单个记录批处理在一起以提高效率。
在acks配置控制下,其请求被认为是完整的标准。我们指定的“all”设置将导致记录完全提交时阻塞,这是最慢但最持久的设置。
如果请求失败,生产者可以自动重试,但由于我们已指定retries 为 0,因此不会。启用重试也开启了重复的可能性(有关详细信息,请参阅有关消息传递语义的文档 )。
生产者为每个分区维护未发送记录的缓冲区。这些缓冲区的大小由batch.size配置指定。将其放大可能会导致更多批处理,但需要更多内存(因为我们通常会为每个活动分区使用这些缓冲区之一)。
默认情况下,即使缓冲区中有额外的未使用空间,也可以立即发送缓冲区。但是,如果您想减少请求的数量,您可以将其设置linger.ms为大于 0 的值。这将指示生产者在发送请求之前等待该毫秒数,希望更多的记录到达以填充同一批。这类似于 TCP 中的 Nagle 算法。例如,在上面的代码片段中,很可能所有 100 条记录都将在单个请求中发送,因为我们将逗留时间设置为 1 毫秒。然而,如果我们没有填满缓冲区,这个设置会给我们的请求增加 1 毫秒的延迟,等待更多的记录到达。请注意,及时到达的记录通常会一起批处理,即使linger.ms=0因此,无论延迟配置如何,都会在重载下发生批处理;然而,将它设置为大于 0 的值可以在不处于最大负载下时以少量延迟为代价导致更少、更高效的请求。
的buffer.memory控制提供给生产者用于缓冲总量的存储器。如果记录的发送速度快于它们可以传输到服务器的速度,则该缓冲区空间将被耗尽。当缓冲区空间耗尽时,额外的发送调用将被阻塞。阻塞时间的阈值取决于max.block.ms它抛出 TimeoutException 之后。
在key.serializer和value.serializer请示如何打开键和值对象的用户与他们的提供ProducerRecord为字节。您可以将包含的ByteArraySerializer或 StringSerializer用于简单的字符串或字节类型。
从 Kafka 0.11 开始,KafkaProducer 支持另外两种模式:幂等生产者和事务性生产者。幂等生产者将 Kafka 的传递语义从至少一次传递到恰好一次传递。特别是生产者重试将不再引入重复。事务生产者允许应用程序以原子方式将消息发送到多个分区(和主题!)。
要启用幂等性,enable.idempotence必须将配置设置为 true。如果设置, retries配置将默认为Integer.MAX_VALUE,acks配置将默认为all. 幂等生产者没有 API 更改,因此无需修改现有应用程序即可利用此功能。
为了利用幂等生产者,必须避免应用程序级别的重新发送,因为这些无法重复数据删除。因此,如果应用程序启用幂等性,建议不要设置retries 配置,因为它将默认为Integer.MAX_VALUE. 此外,如果send(ProducerRecord) 即使无限重试也返回错误(例如,如果消息在发送之前在缓冲区中到期),那么建议关闭生产者并检查最后产生的消息的内容以确保它不是重复。最后,生产者只能保证单个会话内发送的消息的幂等性。
要使用事务性生产者和伴随的 API,您必须设置transactional.id 配置属性。如果transactional.id设置了,则幂等性与幂等性依赖的生产者配置一起自动启用。此外,交易中包含的主题应配置为持久性。特别是,replication.factor应该至少为3,并且 min.insync.replicas这些主题的 应该设置为 2。最后,为了从端到端实现事务性保证,消费者也必须配置为仅读取已提交的消息。
的目的是在transactional.id单个生产者实例的多个会话中启用事务恢复。它通常来自分区的、有状态的应用程序中的分片标识符。因此,它对于在分区应用程序中运行的每个生产者实例应该是唯一的。
所有新的事务 API 都是阻塞的,并且会在失败时抛出异常。下面的示例说明了如何使用新的 API。它类似于上面的示例,不同之处在于所有 100 条消息都是单个事务的一部分。
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("transactional.id", "my-transactional-id");
Producer<String, String> producer = new KafkaProducer<>(props, new StringSerializer(), new StringSerializer());
producer.initTransactions();
try {
producer.beginTransaction();
for (int i = 0; i < 100; i++)
producer.send(new ProducerRecord<>("my-topic", Integer.toString(i), Integer.toString(i)));
producer.commitTransaction();
} catch (ProducerFencedException | OutOfOrderSequenceException | AuthorizationException e) {
// We can't recover from these exceptions, so our only option is to close the producer and exit.
producer.close();
} catch (KafkaException e) {
// For all other exceptions, just abort the transaction and try again.
producer.abortTransaction();
}
producer.close();
正如示例中所暗示的,每个生产者只能有一个打开的事务。在beginTransaction()和commitTransaction()调用之间发送的所有消息 都将成为单个事务的一部分。当 transactional.id指定时,由生产者发送的所有消息必须是事务的一部分。
事务性生产者使用异常来传达错误状态。特别是,不需要为返回的 Future指定回调producer.send()或调用.get(): KafkaException如果任何producer.send()或事务调用在事务期间遇到不可恢复的错误,则将抛出 a 。有关send(ProducerRecord) 从事务性发送中检测错误的更多详细信息,请参阅文档。
通过调用 producer.abortTransaction()接收 aKafkaException我们可以确保任何成功的写入都被标记为中止,从而保持事务保证。