-
Notifications
You must be signed in to change notification settings - Fork 15.4k
MINOR: Producers should set delivery timeout instead of retries #5425
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 3 commits
254c077
f7494dd
81ebf29
7ed56b2
5a1f744
e02c5ec
2d3670b
eae84c1
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 |
|---|---|---|
|
|
@@ -107,10 +107,11 @@ public class ProducerConfig extends AbstractConfig { | |
|
|
||
| /** <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; | ||
| private static final String DELIVERY_TIMEOUT_MS_DOC = "An upper bound on the time to report success or failure after " | ||
| + "Producer.send() returns. The producer may report failure to send a record earlier than this config if all " | ||
| + "the retries have been exhausted or a record is added to a batch nearing expiration. " | ||
| + "The value of this 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; | ||
|
|
@@ -181,10 +182,14 @@ public class ProducerConfig extends AbstractConfig { | |
| /** <code>retries</code> */ | ||
| public static final String RETRIES_CONFIG = CommonClientConfigs.RETRIES_CONFIG; | ||
| private static final String RETRIES_DOC = "Setting a value greater than zero will cause the client to resend any record whose send fails with a potentially transient error." | ||
| + " Note that this retry is no different than if the client resent the record upon receiving the error." | ||
| + " Allowing retries without setting <code>" + MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION + "</code> to 1 will potentially change the" | ||
| + " ordering of records because if two batches are sent to a single partition, and the first fails and is retried but the second" | ||
| + " succeeds, then the records in the second batch may appear first."; | ||
| + " Note that this retry is no different than if the client resent the record upon receiving the error." | ||
| + " Allowing retries without setting <code>" + MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION + "</code> to 1 will potentially change the" | ||
| + " ordering of records because if two batches are sent to a single partition, and the first fails and is retried but the second" | ||
| + " succeeds, then the records in the second batch may appear first. Note that the produce requests will be" | ||
|
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. nit: |
||
| + " failed before the number of retries has been exhausted if the timeout configured by" | ||
| + " " + DELIVERY_TIMEOUT_MS_CONFIG + " expires first before successful acknowledgement. Users should generally" | ||
| + " prefer to leave this config unset and instead use " + DELIVERY_TIMEOUT_MS_CONFIG + " to control" | ||
| + " retry behavior."; | ||
|
|
||
| /** <code>key.serializer</code> */ | ||
| public static final String KEY_SERIALIZER_CLASS_CONFIG = "key.serializer"; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -415,7 +415,7 @@ KafkaBasedLog<String, byte[]> setupAndCreateKafkaBasedLog(String topic, final Wo | |
| Map<String, Object> producerProps = new HashMap<>(originals); | ||
| producerProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); | ||
| producerProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, ByteArraySerializer.class.getName()); | ||
| producerProps.put(ProducerConfig.RETRIES_CONFIG, Integer.MAX_VALUE); | ||
| producerProps.put(ProducerConfig.DELIVERY_TIMEOUT_MS_CONFIG, Integer.MAX_VALUE); | ||
|
Member
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. @rhauch do we need to update Connect documentation? |
||
| Map<String, Object> consumerProps = new HashMap<>(originals); | ||
| consumerProps.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); | ||
| consumerProps.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class.getName()); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -128,7 +128,7 @@ public void configure(final WorkerConfig config) { | |
| Map<String, Object> producerProps = new HashMap<>(originals); | ||
| producerProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); | ||
| producerProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, ByteArraySerializer.class.getName()); | ||
| producerProps.put(ProducerConfig.RETRIES_CONFIG, 0); // we handle retries in this class | ||
| producerProps.put(ProducerConfig.DELIVERY_TIMEOUT_MS_CONFIG, 0); // we handle retries in this class | ||
|
Member
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. Do we really want to do this? Do we ensure that we send the record at least once or could it fail in the accumulator?
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. Actually we probably just want to leave this as it was. |
||
|
|
||
| Map<String, Object> consumerProps = new HashMap<>(originals); | ||
| consumerProps.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -68,9 +68,11 @@ abstract class BaseProducerSendTest extends KafkaServerTestHarness { | |
| super.tearDown() | ||
| } | ||
|
|
||
| protected def createProducer(brokerList: String, retries: Int = 0, lingerMs: Int = 0, props: Option[Properties] = None): KafkaProducer[Array[Byte],Array[Byte]] = { | ||
| protected def createProducer(brokerList: String, | ||
| lingerMs: Int = 0, | ||
| props: Option[Properties] = None): KafkaProducer[Array[Byte],Array[Byte]] = { | ||
| val producer = TestUtils.createProducer(brokerList, securityProtocol = securityProtocol, trustStoreFile = trustStoreFile, | ||
| saslProperties = clientSaslProperties, retries = retries, lingerMs = lingerMs, props = props) | ||
|
Member
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. I was thinking that it would be good to have at least one test with |
||
| saslProperties = clientSaslProperties, lingerMs = lingerMs, props = props) | ||
| registerProducer(producer) | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -619,7 +619,7 @@ class PlaintextConsumerTest extends BaseConsumerTest { | |
| producerProps.setProperty(ProducerConfig.COMPRESSION_TYPE_CONFIG, CompressionType.GZIP.name) | ||
| producerProps.setProperty(ProducerConfig.LINGER_MS_CONFIG, Int.MaxValue.toString) | ||
| val producer = TestUtils.createProducer(brokerList, securityProtocol = securityProtocol, trustStoreFile = trustStoreFile, | ||
| saslProperties = clientSaslProperties, retries = 0, lingerMs = Int.MaxValue, props = Some(producerProps)) | ||
| saslProperties = clientSaslProperties, lingerMs = Int.MaxValue, props = Some(producerProps)) | ||
|
Member
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. Do you know why we were setting this to 0 previously?
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. There was no obvious reason. As far as I can tell, we are just using this function to populate some data in order to check consumer operations. |
||
| (0 until numRecords).foreach { i => | ||
| producer.send(new ProducerRecord(tp.topic, tp.partition, i.toLong, s"key $i".getBytes, s"value $i".getBytes)) | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -304,7 +304,7 @@ class DynamicBrokerReconfigurationTest extends ZooKeeperTestHarness with SaslSet | |
|
|
||
| @Test | ||
| def testLogCleanerConfig(): Unit = { | ||
| val (producerThread, consumerThread) = startProduceConsume(0) | ||
| val (producerThread, consumerThread) = startProduceConsume(retries = 0) | ||
|
|
||
| verifyThreads("kafka-log-cleaner-thread-", countPerBroker = 1) | ||
|
|
||
|
|
@@ -437,7 +437,7 @@ class DynamicBrokerReconfigurationTest extends ZooKeeperTestHarness with SaslSet | |
| def testUncleanLeaderElectionEnable(): Unit = { | ||
| val topic = "testtopic2" | ||
| TestUtils.createTopic(zkClient, topic, 1, replicationFactor = 2, servers) | ||
| val producer = ProducerBuilder().maxRetries(1000).acks(1).build() | ||
| val producer = ProducerBuilder().acks(1).build() | ||
| val consumer = ConsumerBuilder("unclean-leader-test").enableAutoCommit(false).topic(topic).build() | ||
| verifyProduceConsume(producer, consumer, numRecords = 10, topic) | ||
| consumer.commitSync() | ||
|
|
@@ -543,7 +543,7 @@ class DynamicBrokerReconfigurationTest extends ZooKeeperTestHarness with SaslSet | |
| def verifyThreadPoolResize(propName: String, currentSize: => Int, threadPrefix: String, mayReceiveDuplicates: Boolean): Unit = { | ||
| maybeVerifyThreadPoolSize(propName, currentSize, threadPrefix) | ||
| val numRetries = if (mayReceiveDuplicates) 100 else 0 | ||
| val (producerThread, consumerThread) = startProduceConsume(numRetries) | ||
| val (producerThread, consumerThread) = startProduceConsume(retries = numRetries) | ||
| var threadPoolSize = currentSize | ||
| (1 to 2).foreach { _ => | ||
| threadPoolSize = reducePoolSize(propName, threadPoolSize, threadPrefix) | ||
|
|
@@ -1366,7 +1366,7 @@ class DynamicBrokerReconfigurationTest extends ZooKeeperTestHarness with SaslSet | |
| } | ||
|
|
||
| private case class ProducerBuilder() extends ClientBuilder[KafkaProducer[String, String]] { | ||
| private var _retries = 0 | ||
| private var _retries = Int.MaxValue | ||
|
Member
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. Do we just want to remove this?
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. It is being overridden in some cases. |
||
| private var _acks = -1 | ||
| private var _requestTimeoutMs = 30000 | ||
|
|
||
|
|
@@ -1417,8 +1417,9 @@ class DynamicBrokerReconfigurationTest extends ZooKeeperTestHarness with SaslSet | |
| } | ||
| } | ||
|
|
||
| private class ProducerThread(clientId: String, retries: Int) extends | ||
| ShutdownableThread(clientId, isInterruptible = false) { | ||
| private class ProducerThread(clientId: String, retries: Int) | ||
| extends ShutdownableThread(clientId, isInterruptible = false) { | ||
|
|
||
| private val producer = ProducerBuilder().maxRetries(retries).clientId(clientId).build() | ||
| val lastSent = new ConcurrentHashMap[Int, Int]() | ||
| @volatile var sent = 0 | ||
|
|
||
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.
What config is used for "batch expiration"?
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.
Urmm, delivery timeout. I found this wording a little confusing as well. I will try to rephrase.