Class FlinkKafkaProducer<K,​V>

  • All Implemented Interfaces:
    Closeable, AutoCloseable, org.apache.kafka.clients.producer.Producer<K,​V>

    public class FlinkKafkaProducer<K,​V>
    extends Object
    implements org.apache.kafka.clients.producer.Producer<K,​V>
    Wrapper around KafkaProducer that allows to resume transactions in case of node failure, which allows to implement two phase commit algorithm for exactly-once semantic FlinkKafkaProducer.

    For happy path usage is exactly the same as KafkaProducer. User is expected to call:

    To actually implement two phase commit, it must be possible to always commit a transaction after pre-committing it (here, pre-commit is just a flush()). In case of some failure between flush() and commitTransaction() this class allows to resume interrupted transaction and commit if after a restart:

    resumeTransaction(long, short) replaces initTransactions() as a way to obtain the producerId and epoch counters. It has to be done, because otherwise initTransactions() would automatically abort all on going transactions.

    Second way this implementation differs from the reference KafkaProducer is that this one actually flushes new partitions on flush() instead of on commitTransaction().

    The last one minor difference is that it allows to obtain the producerId and epoch counters via getProducerId() and getEpoch() methods (which are unfortunately private fields).

    Those changes are compatible with Kafka's 0.11.0 REST API although it clearly was not the intention of the Kafka's API authors to make them possible.

    Internally this implementation uses KafkaProducer and implements required changes via Java Reflection API. It might not be the prettiest solution. An alternative would be to re-implement whole Kafka's 0.11 REST API client on our own.

    • Constructor Detail

      • FlinkKafkaProducer

        public FlinkKafkaProducer​(Map<String,​Object> properties)
    • Method Detail

      • initTransactions

        public void initTransactions()
        Specified by:
        initTransactions in interface org.apache.kafka.clients.producer.Producer<K,​V>
      • beginTransaction

        public void beginTransaction()
                              throws org.apache.kafka.common.errors.ProducerFencedException
        Specified by:
        beginTransaction in interface org.apache.kafka.clients.producer.Producer<K,​V>
        Throws:
        org.apache.kafka.common.errors.ProducerFencedException
      • commitTransaction

        public void commitTransaction()
                               throws org.apache.kafka.common.errors.ProducerFencedException
        Specified by:
        commitTransaction in interface org.apache.kafka.clients.producer.Producer<K,​V>
        Throws:
        org.apache.kafka.common.errors.ProducerFencedException
      • abortTransaction

        public void abortTransaction()
                              throws org.apache.kafka.common.errors.ProducerFencedException
        Specified by:
        abortTransaction in interface org.apache.kafka.clients.producer.Producer<K,​V>
        Throws:
        org.apache.kafka.common.errors.ProducerFencedException
      • sendOffsetsToTransaction

        public void sendOffsetsToTransaction​(Map<org.apache.kafka.common.TopicPartition,​org.apache.kafka.clients.consumer.OffsetAndMetadata> offsets,
                                             String consumerGroupId)
                                      throws org.apache.kafka.common.errors.ProducerFencedException
        Specified by:
        sendOffsetsToTransaction in interface org.apache.kafka.clients.producer.Producer<K,​V>
        Throws:
        org.apache.kafka.common.errors.ProducerFencedException
      • sendOffsetsToTransaction

        public void sendOffsetsToTransaction​(Map<org.apache.kafka.common.TopicPartition,​org.apache.kafka.clients.consumer.OffsetAndMetadata> offsets,
                                             org.apache.kafka.clients.consumer.ConsumerGroupMetadata groupMetadata)
                                      throws org.apache.kafka.common.errors.ProducerFencedException
        Specified by:
        sendOffsetsToTransaction in interface org.apache.kafka.clients.producer.Producer<K,​V>
        Throws:
        org.apache.kafka.common.errors.ProducerFencedException
      • send

        public Future<org.apache.kafka.clients.producer.RecordMetadata> send​(org.apache.kafka.clients.producer.ProducerRecord<K,​V> record)
        Specified by:
        send in interface org.apache.kafka.clients.producer.Producer<K,​V>
      • send

        public Future<org.apache.kafka.clients.producer.RecordMetadata> send​(org.apache.kafka.clients.producer.ProducerRecord<K,​V> record,
                                                                             org.apache.kafka.clients.producer.Callback callback)
        Specified by:
        send in interface org.apache.kafka.clients.producer.Producer<K,​V>
      • partitionsFor

        public List<org.apache.kafka.common.PartitionInfo> partitionsFor​(String topic)
        Specified by:
        partitionsFor in interface org.apache.kafka.clients.producer.Producer<K,​V>
      • metrics

        public Map<org.apache.kafka.common.MetricName,​? extends org.apache.kafka.common.Metric> metrics()
        Specified by:
        metrics in interface org.apache.kafka.clients.producer.Producer<K,​V>
      • close

        public void close()
        Specified by:
        close in interface AutoCloseable
        Specified by:
        close in interface Closeable
        Specified by:
        close in interface org.apache.kafka.clients.producer.Producer<K,​V>
      • close

        public void close​(Duration timeout)
        Specified by:
        close in interface org.apache.kafka.clients.producer.Producer<K,​V>
      • flush

        public void flush()
        Specified by:
        flush in interface org.apache.kafka.clients.producer.Producer<K,​V>
      • resumeTransaction

        public void resumeTransaction​(long producerId,
                                      short epoch)
        Instead of obtaining producerId and epoch from the transaction coordinator, re-use previously obtained ones, so that we can resume transaction after a restart. Implementation of this method is based on KafkaProducer.initTransactions().
        Parameters:
        producerId - producer id
        epoch - epoch
      • getTransactionalId

        public String getTransactionalId()
      • getProducerId

        public long getProducerId()
      • getEpoch

        public short getEpoch()
      • getTransactionCoordinatorId

        public int getTransactionCoordinatorId()