-
Notifications
You must be signed in to change notification settings - Fork 15.4k
KAFKA-5886: Introduce delivery.timeout.ms producer config (KIP-91) #5270
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,17 @@ | |
| */ | ||
| package org.apache.kafka.clients.producer; | ||
|
|
||
| import java.net.InetSocketAddress; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.Objects; | ||
| import java.util.Properties; | ||
| import java.util.concurrent.ExecutionException; | ||
| import java.util.concurrent.Future; | ||
| import java.util.concurrent.TimeUnit; | ||
| import java.util.concurrent.atomic.AtomicInteger; | ||
| import java.util.concurrent.atomic.AtomicReference; | ||
| import org.apache.kafka.clients.ApiVersions; | ||
| import org.apache.kafka.clients.ClientUtils; | ||
| import org.apache.kafka.clients.KafkaClient; | ||
|
|
@@ -24,6 +35,7 @@ | |
| import org.apache.kafka.clients.consumer.KafkaConsumer; | ||
| import org.apache.kafka.clients.consumer.OffsetAndMetadata; | ||
| import org.apache.kafka.clients.consumer.OffsetCommitCallback; | ||
| import org.apache.kafka.clients.producer.internals.BufferPool; | ||
| import org.apache.kafka.clients.producer.internals.ProducerInterceptors; | ||
| import org.apache.kafka.clients.producer.internals.ProducerMetrics; | ||
| import org.apache.kafka.clients.producer.internals.RecordAccumulator; | ||
|
|
@@ -69,18 +81,6 @@ | |
| import org.apache.kafka.common.utils.Time; | ||
| import org.slf4j.Logger; | ||
|
|
||
| import java.net.InetSocketAddress; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.Objects; | ||
| import java.util.Properties; | ||
| import java.util.concurrent.ExecutionException; | ||
| import java.util.concurrent.Future; | ||
| import java.util.concurrent.TimeUnit; | ||
| import java.util.concurrent.atomic.AtomicInteger; | ||
| import java.util.concurrent.atomic.AtomicReference; | ||
|
|
||
| import static org.apache.kafka.common.serialization.ExtendedSerializer.Wrapper.ensureExtended; | ||
|
|
||
| /** | ||
|
|
@@ -235,6 +235,7 @@ public class KafkaProducer<K, V> implements Producer<K, V> { | |
| private static final AtomicInteger PRODUCER_CLIENT_ID_SEQUENCE = new AtomicInteger(1); | ||
| private static final String JMX_PREFIX = "kafka.producer"; | ||
| public static final String NETWORK_THREAD_PREFIX = "kafka-producer-network-thread"; | ||
| public static final String PRODUCER_METRIC_GROUP_NAME = "producer-metrics"; | ||
|
|
||
| private final String clientId; | ||
| // Visible for testing | ||
|
|
@@ -392,18 +393,21 @@ public KafkaProducer(Properties properties, Serializer<K> keySerializer, Seriali | |
| int retries = configureRetries(config, transactionManager != null, log); | ||
| int maxInflightRequests = configureInflightRequests(config, transactionManager != null); | ||
| short acks = configureAcks(config, transactionManager != null, log); | ||
| int deliveryTimeoutMs = configureDeliveryTimeout(config, log); | ||
|
|
||
| this.apiVersions = new ApiVersions(); | ||
| this.accumulator = new RecordAccumulator(logContext, | ||
| config.getInt(ProducerConfig.BATCH_SIZE_CONFIG), | ||
| this.totalMemorySize, | ||
| this.compressionType, | ||
| config.getLong(ProducerConfig.LINGER_MS_CONFIG), | ||
| config.getInt(ProducerConfig.LINGER_MS_CONFIG), | ||
| retryBackoffMs, | ||
| deliveryTimeoutMs, | ||
| metrics, | ||
| PRODUCER_METRIC_GROUP_NAME, | ||
| time, | ||
| apiVersions, | ||
| transactionManager); | ||
| transactionManager, | ||
| new BufferPool(this.totalMemorySize, config.getInt(ProducerConfig.BATCH_SIZE_CONFIG), metrics, time, PRODUCER_METRIC_GROUP_NAME)); | ||
| List<InetSocketAddress> addresses = ClientUtils.parseAndValidateAddresses(config.getList(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG)); | ||
| if (metadata != null) { | ||
| this.metadata = metadata; | ||
|
|
@@ -459,10 +463,30 @@ public KafkaProducer(Properties properties, Serializer<K> keySerializer, Seriali | |
| } | ||
| } | ||
|
|
||
| private static TransactionManager configureTransactionState(ProducerConfig config, LogContext logContext, Logger log) { | ||
| private static int configureDeliveryTimeout(ProducerConfig config, Logger log) { | ||
| int deliveryTimeoutMs = config.getInt(ProducerConfig.DELIVERY_TIMEOUT_MS_CONFIG); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be of type long ? In ProducerBatch, deliveryTimeoutMs is long in hasReachedDeliveryTimeout
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| int lingerMs = config.getInt(ProducerConfig.LINGER_MS_CONFIG); | ||
| int requestTimeoutMs = config.getInt(ProducerConfig.REQUEST_TIMEOUT_MS_CONFIG); | ||
|
|
||
| if (deliveryTimeoutMs < Integer.MAX_VALUE && deliveryTimeoutMs < lingerMs + requestTimeoutMs) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (deliveryTimeoutMs < lingerMs + requestTimeoutMs) implies (deliveryTimeoutMs < Integer.MAX_VALUE), why do we need to check (deliveryTimeoutMs < Integer.MAX_VALUE), logically it can be removed. |
||
| if (config.originals().containsKey(ProducerConfig.DELIVERY_TIMEOUT_MS_CONFIG)) { | ||
| // throw an exception if the user explicitly set an inconsistent value | ||
| throw new ConfigException(ProducerConfig.DELIVERY_TIMEOUT_MS_CONFIG | ||
| + " should be equal to or larger than " + ProducerConfig.LINGER_MS_CONFIG | ||
| + " + " + ProducerConfig.REQUEST_TIMEOUT_MS_CONFIG); | ||
| } else { | ||
| // override deliveryTimeoutMs default value to lingerMs + requestTimeoutMs for backward compatibility | ||
| deliveryTimeoutMs = lingerMs + requestTimeoutMs; | ||
| log.warn("{} should be equal to or larger than {} + {}. Setting it to {}.", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't need to be warn.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is try to get the user's attention as we are overriding the default delivery.timeout.ms setting. Previously the user may set a long |
||
| ProducerConfig.DELIVERY_TIMEOUT_MS_CONFIG, ProducerConfig.LINGER_MS_CONFIG, | ||
| ProducerConfig.REQUEST_TIMEOUT_MS_CONFIG, deliveryTimeoutMs); | ||
| } | ||
| } | ||
| return deliveryTimeoutMs; | ||
| } | ||
|
|
||
| private static TransactionManager configureTransactionState(ProducerConfig config, LogContext logContext, Logger log) { | ||
| TransactionManager transactionManager = null; | ||
|
|
||
| boolean userConfiguredIdempotence = false; | ||
| if (config.originals().containsKey(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG)) | ||
| userConfiguredIdempotence = true; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -99,6 +99,19 @@ public class ProducerConfig extends AbstractConfig { | |
| + "specified time waiting for more records to show up. This setting defaults to 0 (i.e. no delay). Setting <code>" + LINGER_MS_CONFIG + "=5</code>, " | ||
| + "for example, would have the effect of reducing the number of requests sent but would add up to 5ms of latency to records sent in the absence of load."; | ||
|
|
||
| /** <code>request.timeout.ms</code> */ | ||
| public static final String REQUEST_TIMEOUT_MS_CONFIG = CommonClientConfigs.REQUEST_TIMEOUT_MS_CONFIG; | ||
| private static final String REQUEST_TIMEOUT_MS_DOC = CommonClientConfigs.REQUEST_TIMEOUT_MS_DOC | ||
| + " This should be larger than replica.lag.time.max.ms (a broker configuration)" | ||
| + " to reduce the possibility of message duplication due to unnecessary producer retries."; | ||
|
|
||
| /** <code>delivery.timeout.ms</code> */ | ||
| public static final String DELIVERY_TIMEOUT_MS_CONFIG = "delivery.timeout.ms"; | ||
| private static final String DELIVERY_TIMEOUT_MS_DOC = "An upper bound on the time to report success or failure after Producer.send() returns. " | ||
| + "Producer may report failure to send a message earlier than this config if all the retries are exhausted or " | ||
| + "a record is added to a batch nearing expiration. " + DELIVERY_TIMEOUT_MS_CONFIG + "should be equal to or " | ||
| + "greater than " + REQUEST_TIMEOUT_MS_CONFIG + " + " + LINGER_MS_CONFIG; | ||
|
|
||
| /** <code>client.id</code> */ | ||
| public static final String CLIENT_ID_CONFIG = CommonClientConfigs.CLIENT_ID_CONFIG; | ||
|
|
||
|
|
@@ -188,12 +201,6 @@ public class ProducerConfig extends AbstractConfig { | |
| public static final String PARTITIONER_CLASS_CONFIG = "partitioner.class"; | ||
| private static final String PARTITIONER_CLASS_DOC = "Partitioner class that implements the <code>org.apache.kafka.clients.producer.Partitioner</code> interface."; | ||
|
|
||
| /** <code>request.timeout.ms</code> */ | ||
| public static final String REQUEST_TIMEOUT_MS_CONFIG = CommonClientConfigs.REQUEST_TIMEOUT_MS_CONFIG; | ||
| private static final String REQUEST_TIMEOUT_MS_DOC = CommonClientConfigs.REQUEST_TIMEOUT_MS_DOC | ||
| + " This should be larger than replica.lag.time.max.ms (a broker configuration)" | ||
| + " to reduce the possibility of message duplication due to unnecessary producer retries."; | ||
|
|
||
| /** <code>interceptor.classes</code> */ | ||
| public static final String INTERCEPTOR_CLASSES_CONFIG = "interceptor.classes"; | ||
| public static final String INTERCEPTOR_CLASSES_DOC = "A list of classes to use as interceptors. " | ||
|
|
@@ -224,7 +231,7 @@ public class ProducerConfig extends AbstractConfig { | |
| static { | ||
| CONFIG = new ConfigDef().define(BOOTSTRAP_SERVERS_CONFIG, Type.LIST, Collections.emptyList(), new ConfigDef.NonNullValidator(), Importance.HIGH, CommonClientConfigs.BOOTSTRAP_SERVERS_DOC) | ||
| .define(BUFFER_MEMORY_CONFIG, Type.LONG, 32 * 1024 * 1024L, atLeast(0L), Importance.HIGH, BUFFER_MEMORY_DOC) | ||
| .define(RETRIES_CONFIG, Type.INT, 0, between(0, Integer.MAX_VALUE), Importance.HIGH, RETRIES_DOC) | ||
| .define(RETRIES_CONFIG, Type.INT, Integer.MAX_VALUE, between(0, Integer.MAX_VALUE), Importance.HIGH, RETRIES_DOC) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you mention this default change in the upgrade notes?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated the upgrade doc on this. |
||
| .define(ACKS_CONFIG, | ||
| Type.STRING, | ||
| "1", | ||
|
|
@@ -233,7 +240,8 @@ public class ProducerConfig extends AbstractConfig { | |
| ACKS_DOC) | ||
| .define(COMPRESSION_TYPE_CONFIG, Type.STRING, "none", Importance.HIGH, COMPRESSION_TYPE_DOC) | ||
| .define(BATCH_SIZE_CONFIG, Type.INT, 16384, atLeast(0), Importance.MEDIUM, BATCH_SIZE_DOC) | ||
| .define(LINGER_MS_CONFIG, Type.LONG, 0, atLeast(0L), Importance.MEDIUM, LINGER_MS_DOC) | ||
| .define(LINGER_MS_CONFIG, Type.INT, 0, atLeast(0), Importance.MEDIUM, LINGER_MS_DOC) | ||
| .define(DELIVERY_TIMEOUT_MS_CONFIG, Type.INT, 120 * 1000, atLeast(0), Importance.MEDIUM, DELIVERY_TIMEOUT_MS_DOC) | ||
| .define(CLIENT_ID_CONFIG, Type.STRING, "", Importance.MEDIUM, CommonClientConfigs.CLIENT_ID_DOC) | ||
| .define(SEND_BUFFER_CONFIG, Type.INT, 128 * 1024, atLeast(-1), Importance.MEDIUM, CommonClientConfigs.SEND_BUFFER_DOC) | ||
| .define(RECEIVE_BUFFER_CONFIG, Type.INT, 32 * 1024, atLeast(-1), Importance.MEDIUM, CommonClientConfigs.RECEIVE_BUFFER_DOC) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why changing linger to int ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have
request.timeout.msanddelivery.timeout.msofinttype. this is to make the type oflinger.msbe consistent with other timeout related settings.