KAFKA-20976: Make max partitions per request configurable - #23245
KAFKA-20976: Make max partitions per request configurable#23245andrewgrantcflt wants to merge 8 commits into
Conversation
| public static final long CONTROLLER_PERFORMANCE_ALWAYS_LOG_THRESHOLD_MS_DEFAULT = 2000; | ||
| public static final String CONTROLLER_PERFORMANCE_ALWAYS_LOG_THRESHOLD_MS_DOC = "We will log an error message about controller events that take longer than this threshold."; | ||
|
|
||
| public static final String CONTROLLER_MAX_PARTITIONS_PER_BATCH_CONFIG = "controller.max.partitions.per.batch"; |
There was a problem hiding this comment.
I considered naming the config controller.max.partitions.per.create.topics.batch as well. As of now, this config is only used when handling CREATE_TOPICS requests so arguably that name may be clearer. controller.max.partitions.per.batch is a bit generic and could imply it is used for other RPCs, but maybe that's better if we want to reuse this config in the future, for example for CREATE_PARTITIONS?
Curious to hear other folks' opinions.
There was a problem hiding this comment.
I put the config in KRaftConfigs since it's only to be used by the controller.
AndrewJSchofield
left a comment
There was a problem hiding this comment.
Thanks for the PR. I don't like adding the config without a KIP, but this is an internal-only config and it is making a hard-coded limit configurable. I reckon it sneaks in under the KIP bar :)
I do suggest making it a bit more general-purposes in the ReplicationControlManager. For example, deleteTopics and others limit the request size to MAX_RECORDS_PER_USER_OP, which is also 10000. Aren't these essentially the same thing, checking that the user operation is not too complex for the controller to handle? Let me know if that makes sense too.
| public static final String CONTROLLER_MAX_PARTITIONS_PER_BATCH_CONFIG = "controller.max.partitions.per.batch"; | ||
| public static final int CONTROLLER_MAX_PARTITIONS_PER_BATCH_DEFAULT = 10_000; | ||
| public static final String CONTROLLER_MAX_PARTITIONS_PER_BATCH_DOC = "The maximum number of partitions that the " + | ||
| "active controller will allow to be created by a single CreateTopics request. This limit protects the " + |
There was a problem hiding this comment.
Can we make this a bit less specific by removing the "CreateTopics" part of this?
There was a problem hiding this comment.
Agreed. Updated, especially as now the config is used in other places where we had the 10,000 limit for the max number of metadata records we can add to a single batch.
@AndrewJSchofield and I chatted. I am going to close this PR because it's a bit controversial adding a config without a KIP. |
|
This area is ripe for a KIP as part of the ongoing work to harden the Kafka protocol. |
|
Re-opening the PR. After chatting with @AndrewJSchofield, @jsancio and @rajinisivaram, it should be OK to add an internal config without a KIP if we include an integration test showing it in use. |
|
@andrewgrantcflt Checkstyle failure |
Thanks, fixing it. |
AndrewJSchofield
left a comment
There was a problem hiding this comment.
Thanks for the updated PR. It's good to see all of the related operations use the same config now. Just a few comments, but it's getting there.
| setQuorumFeatures(quorumFeatures). | ||
| setDefaultReplicationFactor(config.defaultReplicationFactor.toShort). | ||
| setDefaultNumPartitions(config.numPartitions.intValue()). | ||
| setMaxRecordsPerBatch(config.controllerMaxRecordsPerBatch). |
There was a problem hiding this comment.
nit: Any reason why this config is not added at the end, preserving the order after controllerPerformanceAlwaysLogThresholdMs?
There was a problem hiding this comment.
Hmm no good reason. I will move it.
| } | ||
| if (totalPartitions > MAX_PARTITIONS_PER_BATCH) { | ||
| if (totalPartitions > maxRecordsPerBatch) { | ||
| throw new PolicyViolationException("Excessively large number of partitions per request."); |
There was a problem hiding this comment.
This exception message is really not that elegant. It sounds like the configuration for the number of partitions per request is excessive, but actually it's just complaining about an individual request. How about something like "Too many partitions in request".
There was a problem hiding this comment.
I do agree. Is it OK to change the error message? I know users probably shouldn't be depending on the message, but in practice it inevitably will happen.
There was a problem hiding this comment.
Yes, you can change it.
| ControllerResult<ElectLeadersResponseData> electLeaders(ElectLeadersRequestData request) { | ||
| ElectionType electionType = electionType(request.electionType()); | ||
| List<ApiMessageAndVersion> records = BoundedList.newArrayBacked(MAX_RECORDS_PER_USER_OP); | ||
| List<ApiMessageAndVersion> records = BoundedList.newArrayBacked(maxRecordsPerBatch); |
There was a problem hiding this comment.
Just an observation from reading an unfamiliar area of code. This is going to result in a BoundedListTooLongException if the list capacity is exceeded, I think. Any reason why validateTotalNumberOfPartitions is taking a different path?
There was a problem hiding this comment.
I'm not too sure. I do see the following:
https://github.com/apache/kafka/blob/trunk/metadata/src/main/java/org/apache/kafka/controller/errors/EventHandlerExceptionInfo.java#L83-L88
} else if (internal instanceof BoundedListTooLongException) {
// The operation could not be performed because it would have created an overly large
// batch.
return new EventHandlerExceptionInfo(false, false, internal,
new PolicyViolationException("Unable to perform excessively large batch " +
"operation."));
I think BoundedListTooLongException does eventually get mapped to the same exception, albeit with a different error message. I probably would have made the code that throws BoundedListTooLongException catch it and re-throw a PolicyViolationException directly but that's probably out of scope for this PR.
Description
In
ReplicationControlManagerthere is a max of 10,000 partitionsallowed in a single create topics request. In an app I am seeing this
limit being hit. I am trying to reproduce the error in an integration
test, but by having to create so many partitions the test is slow and
flaky. I have to create up to 10,000 partitions to reproduce the issue
because the limit is currently hard-coded.
So here I am simply making the limit a config. By having it as a config,
we can configure the limit to be lower and reproduce the issue in a test
without having to create so many partitions.
In fact, the current limit of 10,000 comes from the fact that we should
only add 10,000 records to a single batch that gets persisted to the
metadata log. We use that same 10,000 limit in a few other places, such
as when handling
DELETE_TOPICS. There we useMAX_RECORDS_PER_USER_OPwhen creating a bounded array. Ultimately all of these limits are
related in that we want to not add more than 10,000 records to a single
batch. So I refactor some code that uses that same limit to use the same
config I have added.
https: //issues.apache.org/jira/browse/KAFKA-20976 Reviewers: Andrew
Schofield aschofield@confluent.io
Reviewers: Andrew Schofield aschofield@confluent.io