kafkaProducer


kafkaProducer概述

kafkaproducer是发送record到kafka集群的Kafka客户端。

Kafkaproducer是线程安全的,线程之间共享单个producer实例比拥有多个实例更快。

以下是使用producer发送包含连续号码的string字符串作为键/值对的record的示例。

 Properties props = new Properties();
 props.put("bootstrap.servers", "localhost:9092");
 props.put("acks", "all");
 props.put("retries", 0);
 props.put("batch.size", 16384);
 props.put("linger.ms", 1);
 props.put("buffer.memory", 33554432);
 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();

kafkaProducer是由一池Buffer space(即缓冲池)组成的,buffer space会保持还没提交到server的record,

同时background I/O线程把这些record转换成request并传输到cluster中。使用后如果没有关闭producer会导致
resource溢出。

kafkaProducer的send()方法是异步的,当调用这个方法时会添加record到Buffer中,然后立即返回。这样可以
批处理单条record,变得更加高效。


ack配置控制request被认为完成的标准。 我们指定的“all”设置会导致record的完整提交被阻塞,这是最慢但最持久的设置

如果request失败,producer可以自动重试,但由于我们将重试次数指定为0,它不会。 启用重试也会导致重复的可能性。


producer维护每个partition中未发送record的Buffer。 这些buffer的大小由batch.size配置指定。 使其更大可以导致更多的批处理,但需要更多的内存(因为我们通常每个活动partition都有这些缓冲区中的一个)。


默认情况下,即使Buffer中存在额外的未使用空间,Buffer也可立即发送。但是,如果你想减少request的数量,你可以将linger.ms设置为大于0的值。这将指示producer在发送请求之前等待这个毫秒数,以期望更多的record到达以填满同一批次。这与TCP中的Nagle算法类似。例如,在上面的代码片段中,由于我们将逗留时间设置为1毫秒,因此可能所有100条记录都将在单个请求中发送。然而,如果我们没有填充缓冲区,这个设置会给我们的请求增加1毫秒的延迟,等待更多的记录到达。请注意,即使在linger.ms = 0的情况下,到达时间接近的record通常也会一起批处理,因此在重负载下,无论linger配置如何,都会发生配料;然而,将此设置为大于0的值可能导致在不处于最大负载时,以较少延迟为代价,获得更少,更高效的请求。


buffer.memory控制producer用于Buffer的总内存量。 如果record的发送速度比它们可以传送到server的速度快,那么这个buffer space将会很快被填满空间。 当Buffer space空间耗尽时,其它send call将被阻塞。 阻塞时间的阈值由max.block.ms决定,之后它会引发TimeoutException


用户会给ProducerRecord提供键值对对象,key.serializer和value.serializer指示如何将这些键值对对象转换为字节。 您可以使用包含的ByteArraySerializer或StringSerializer作为简单的字符串或字节类型。


从Kafka 0.11开始,KafkaProducer支持另外两种模式:idempotent producer和transactionial producer。 idempotent producer将kafka的delivery semantics(交付语义)从at least once加强到exactly once。 特别是producer重试将不再引入dupliactes。 transactional producer允许应用程序自动发送消息到多个partition(和topic)中去。


要启用idempotence,必须将enable.idempotence配置设置为true。 如果设置,retries config(重试配置)将默认为Integer.MAX_VALUE,max.in.flight.requests.per.connection配置将默认为1,并且ack配置默认为all。 idempotent producer没有API更改,所以现有的应用程序将不需要修改以利用此功能。


为了利用idempotent producer,必须避免应用程序级别的re-send,因为这些不能被重复删除。 因此,如果应用程序启用了idempotence,则建议不要设置retries config(重试配置),因为它将默认为Integer.MAX_VALUE。 此外,如果发送(ProducerRecord)返回错误,即使进行无限次重试也无济于事(例如,消息在发送前在缓冲区中到期),建议关闭producer并检查最后生成的消息的内容以确保 它不重复。 最后, producer只能保证在single Session中发送的message的idempotence(幂等性)。


要使用transactionial producer和伴随的API,您必须设置transactional.id配置属性。 如果设置了transactional.id,则idempotence会自动启用,同时producer配置哪个idempotence依赖于哪个。此外,transaction中包含的topic应配置为耐用性。特别地,replication.factor应该至少为3,并且这些topic的min.insync.replicas应该设置为2.最后,为了使事务保证从end-to-end实现,consumer必须是配置为只读取已提交的消息。


transactional.id的目的是在单个producer instance的多个Session中启用事务恢复(transaction recovery)。它通常来自分区的有状态应用程序中的 shard identifier(碎片标识符)。因此,对于在partitioned application(分区应用程序)中运行的 每个producer instance而言,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时,生产者发送的所有消息都必须是事务的一部分。

Transactional producer使用异常来传达错误状态。特别是,不需要为producer.send()指定回调或在返回的Future上调用.get():如果任何producer.send()或事务性调用在执行期间遇到不可恢复的错误时,将抛出KafkaException。有关检测事务性发送错误的更多详细信息,请参阅send(ProducerRecord)文档。

通过在收到KafkaException异常时调用producer.abortTransaction(),我们可以确保任何成功的写入被标记为中止,因此保持事务性保证。

该客户端可以与0.10.0或更新版本的broker进行通信。较早或较新的broker可能不支持某些客户端功能。


kafkaProducer对象的initTransaction()

需要在任何其它方法之前被调用,当在configuration中有使用transaction.id时。这个方法会如下工作:
1、保证已经被之前的producer实例初始化的拥有相同transaction.id的transaction能够完成。
   如果之前的实例在一个进程中事务失败了,它会被丢弃。如果最后一个事务已经开始完成了,但还没完成,
   这个方法会等待它的完成。

2、 获取内部的producer id和epoch。在以后producer发送的transaction message中都会使用到它们


译自: kafkaProducer api文档






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值