-
Notifications
You must be signed in to change notification settings - Fork 15.4k
KAFKA-6718 / A Rack awareness for Kafka Streams #10785
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
Closed
lkokhreidze
wants to merge
28
commits into
apache:trunk
from
lkokhreidze:KAFKA-6718-rack-awareness-for-kafka-streams
Closed
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
663ebde
KAFKA-6718 / Add new configurations to StreamsConfig
lkokhreidze 75b2399
KAFKA-6718 / [Cleanup] Add new configurations to StreamsConfig
lkokhreidze 9df44a7
KAFKA-6718 / Add StreamsConfig tests
lkokhreidze c60b457
KAFKA-6718 / Update SubscriptionInfoData.json with ClientTag struct
lkokhreidze 52c1ed7
KAFKA-6718 / Encode client tags in SubscriptionInfo
lkokhreidze bfc9295
KAFKA-6718 / Algorithm implementation
lkokhreidze 8065b06
KAFKA-6718 / merge
lkokhreidze 7e9ae0a
KAFKA-6718 / Cleanup code
lkokhreidze 7b1ded0
Merge branch 'trunk' into KAFKA-6718-rack-awareness-for-kafka-streams
lkokhreidze 395cb8c
KAFKA-6718 / Add rack awareness related config validation
lkokhreidze 1c1d7af
KAFKA-6718 / Add tests
lkokhreidze 690f838
KAFKA-6718 / Add more unit tests
lkokhreidze 6230145
KAFKA-6718 / Fix HighAvailabilityTaskAssignorTest
lkokhreidze 9fb581f
KAFKA-6718 / Revert build.gradle change
lkokhreidze 46f44d9
KAFKA-6718 / fix tests
lkokhreidze 04aae82
KAFKA-6718 / Add StandbyTaskAssignorInitializerTest
lkokhreidze fa59a4e
KAFKA-6718 / Simplify task assignment logic and add more tests
lkokhreidze 4f0ca6c
KAFKA-6718 / Add more tests
lkokhreidze fd64d32
KAFKA-6718 / Improve log line
lkokhreidze 2db3a50
KAFKA-6718 / More validation rules
lkokhreidze 9b7e9db
KAFKA-6718 / Remove log line
lkokhreidze a4c90bf
KAFKA-6718 / Simplify logic; Add more unit tests; Fix StreamsPartitio…
lkokhreidze 84e620c
KAFKA-6718 / Add ConfigDefTest for the ListSize validator
lkokhreidze 68eab46
KAFKA-6718 / Rename variable
lkokhreidze c6b95f7
Merge branch 'trunk' into KAFKA-6718-rack-awareness-for-kafka-streams
lkokhreidze c298ab4
KAFKA-6718 / Update streams_upgrade_test and add unit test
lkokhreidze 404c511
KAFKA-6718 / Fix StreamsUpgradeTest
lkokhreidze 99eb202
Merge branch 'trunk' into KAFKA-6718-rack-awareness-for-kafka-streams
lkokhreidze File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,12 +49,16 @@ | |
| import java.time.Duration; | ||
| import java.util.Collections; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Locale; | ||
| import java.util.Map; | ||
| import java.util.Objects; | ||
| import java.util.Properties; | ||
| import java.util.Set; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| import static org.apache.kafka.common.IsolationLevel.READ_COMMITTED; | ||
| import static org.apache.kafka.common.config.ConfigDef.ListSize.max; | ||
| import static org.apache.kafka.common.config.ConfigDef.Range.atLeast; | ||
| import static org.apache.kafka.common.config.ConfigDef.Range.between; | ||
| import static org.apache.kafka.common.config.ConfigDef.ValidString.in; | ||
|
|
@@ -146,9 +150,11 @@ public class StreamsConfig extends AbstractConfig { | |
| private static final long DEFAULT_COMMIT_INTERVAL_MS = 30000L; | ||
| private static final long EOS_DEFAULT_COMMIT_INTERVAL_MS = 100L; | ||
| private static final int DEFAULT_TRANSACTION_TIMEOUT = 10000; | ||
| private static final short DEFAULT_MAX_CLIENT_TAG_KEY_VALUE_LENGTH = 40; | ||
|
|
||
| public static final int DUMMY_THREAD_INDEX = 1; | ||
| public static final long MAX_TASK_IDLE_MS_DISABLED = -1; | ||
| public static final int MAX_RACK_AWARE_ASSIGNMENT_TAG_LIST_SIZE = 5; | ||
|
|
||
| /** | ||
| * Prefix used to provide default topic configs to be applied when creating internal topics. | ||
|
|
@@ -214,6 +220,15 @@ public class StreamsConfig extends AbstractConfig { | |
| @SuppressWarnings("WeakerAccess") | ||
| public static final String ADMIN_CLIENT_PREFIX = "admin."; | ||
|
|
||
| /** | ||
| * Prefix used to add arbitrary tags to a Kafka Stream's instance as key-value pairs. | ||
| * Example: | ||
| * client.tag.zone=zone1 | ||
| * client.tag.cluster=cluster1 | ||
| */ | ||
| @SuppressWarnings("WeakerAccess") | ||
| public static final String CLIENT_TAG_PREFIX = "client.tag."; | ||
|
|
||
| /** | ||
| * Config value for parameter {@link #TOPOLOGY_OPTIMIZATION_CONFIG "topology.optimization"} for disabling topology optimization | ||
| */ | ||
|
|
@@ -427,6 +442,10 @@ public class StreamsConfig extends AbstractConfig { | |
| public static final String DEFAULT_TIMESTAMP_EXTRACTOR_CLASS_CONFIG = "default.timestamp.extractor"; | ||
| private static final String DEFAULT_TIMESTAMP_EXTRACTOR_CLASS_DOC = "Default timestamp extractor class that implements the <code>org.apache.kafka.streams.processor.TimestampExtractor</code> interface."; | ||
|
|
||
| /** {@code max.client.tag.length} */ | ||
| public static final String MAX_CLIENT_TAG_KEY_VALUE_LENGTH_CONFIG = "max.client.tag.key.value.length"; | ||
| private static final String MAX_CLIENT_TAG_KEY_VALUE_LENGTH_DOC = "The maximum length of key-value pairs set via " + CLIENT_TAG_PREFIX + " configuration prefix."; | ||
|
|
||
| /** {@code max.task.idle.ms} */ | ||
| public static final String MAX_TASK_IDLE_MS_CONFIG = "max.task.idle.ms"; | ||
| private static final String MAX_TASK_IDLE_MS_DOC = "Maximum amount of time in milliseconds a stream task will stay idle when not all of its partition buffers contain records," + | ||
|
|
@@ -494,6 +513,13 @@ public class StreamsConfig extends AbstractConfig { | |
| @SuppressWarnings("WeakerAccess") | ||
| public static final String RECEIVE_BUFFER_CONFIG = CommonClientConfigs.RECEIVE_BUFFER_CONFIG; | ||
|
|
||
| /** {@code rack.aware.assignment.tags} */ | ||
| @SuppressWarnings("WeakerAccess") | ||
| public static final String RACK_AWARE_ASSIGNMENT_TAGS_CONFIG = "rack.aware.assignment.tags"; | ||
| private static final String RACK_AWARE_ASSIGNMENT_TAGS_DOC = "List of client tag keys used to distribute standby replicas across Kafka Streams instances." + | ||
| " When configured, Kafka Streams will make a best-effort to distribute" + | ||
| " the standby tasks over each client tag dimension."; | ||
|
|
||
| /** {@code reconnect.backoff.ms} */ | ||
| @SuppressWarnings("WeakerAccess") | ||
| public static final String RECONNECT_BACKOFF_MS_CONFIG = CommonClientConfigs.RECONNECT_BACKOFF_MS_CONFIG; | ||
|
|
@@ -599,6 +625,7 @@ public class StreamsConfig extends AbstractConfig { | |
| ProducerConfig.TRANSACTIONAL_ID_CONFIG | ||
| }; | ||
|
|
||
|
|
||
| static { | ||
| CONFIG = new ConfigDef() | ||
|
|
||
|
|
@@ -714,6 +741,12 @@ public class StreamsConfig extends AbstractConfig { | |
| -1, | ||
| Importance.MEDIUM, | ||
| REPLICATION_FACTOR_DOC) | ||
| .define(RACK_AWARE_ASSIGNMENT_TAGS_CONFIG, | ||
| Type.LIST, | ||
| Collections.emptyList(), | ||
| max(MAX_RACK_AWARE_ASSIGNMENT_TAG_LIST_SIZE), | ||
| Importance.MEDIUM, | ||
| RACK_AWARE_ASSIGNMENT_TAGS_DOC) | ||
| .define(SECURITY_PROTOCOL_CONFIG, | ||
| Type.STRING, | ||
| CommonClientConfigs.DEFAULT_SECURITY_PROTOCOL, | ||
|
|
@@ -763,6 +796,12 @@ public class StreamsConfig extends AbstractConfig { | |
| 9 * 60 * 1000L, | ||
| ConfigDef.Importance.LOW, | ||
| CommonClientConfigs.CONNECTIONS_MAX_IDLE_MS_DOC) | ||
| .define(MAX_CLIENT_TAG_KEY_VALUE_LENGTH_CONFIG, | ||
| Type.SHORT, | ||
| DEFAULT_MAX_CLIENT_TAG_KEY_VALUE_LENGTH, | ||
| between(1, 200), | ||
| Importance.LOW, | ||
| MAX_CLIENT_TAG_KEY_VALUE_LENGTH_DOC) | ||
| .define(METADATA_MAX_AGE_CONFIG, | ||
| ConfigDef.Type.LONG, | ||
| 5 * 60 * 1000L, | ||
|
|
@@ -1024,6 +1063,16 @@ public static String adminClientPrefix(final String adminClientProp) { | |
| return ADMIN_CLIENT_PREFIX + adminClientProp; | ||
| } | ||
|
|
||
| /** | ||
| * Prefix a client tag key with {@link #CLIENT_TAG_PREFIX}. | ||
| * | ||
| * @param clientTagKey client tag key | ||
| * @return {@link #CLIENT_TAG_PREFIX} + {@code clientTagKey} | ||
| */ | ||
| public static String clientTagPrefix(final String clientTagKey) { | ||
| return CLIENT_TAG_PREFIX + clientTagKey; | ||
| } | ||
|
|
||
| /** | ||
| * Prefix a property with {@link #TOPIC_PREFIX} | ||
| * used to provide default topic configs to be applied when creating internal topics. | ||
|
|
@@ -1107,6 +1156,38 @@ protected Map<String, Object> postProcessParsedConfig(final Map<String, Object> | |
| configUpdates.put(COMMIT_INTERVAL_MS_CONFIG, EOS_DEFAULT_COMMIT_INTERVAL_MS); | ||
| } | ||
|
|
||
| // validate rack awareness related configuration | ||
| final short maxClientTagKeyValueLength = getShort(MAX_CLIENT_TAG_KEY_VALUE_LENGTH_CONFIG); | ||
| final List<String> rackAwareAssignmentTags = getList(RACK_AWARE_ASSIGNMENT_TAGS_CONFIG); | ||
| final Map<String, String> clientTags = getClientTags(); | ||
|
|
||
| if (clientTags.size() > MAX_RACK_AWARE_ASSIGNMENT_TAG_LIST_SIZE) { | ||
| throw new ConfigException("At most " + MAX_RACK_AWARE_ASSIGNMENT_TAG_LIST_SIZE + " client tags " + | ||
| "can be specified using " + CLIENT_TAG_PREFIX + " prefix."); | ||
| } | ||
|
|
||
| for (final String rackAwareAssignmentTag : rackAwareAssignmentTags) { | ||
|
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. Not sure if doing validations in |
||
| if (!clientTags.containsKey(rackAwareAssignmentTag)) { | ||
| throw new ConfigException(RACK_AWARE_ASSIGNMENT_TAGS_CONFIG, | ||
| rackAwareAssignmentTags, | ||
| "Contains invalid value [" + rackAwareAssignmentTag + "] " + | ||
| "which doesn't have corresponding tag set via [" + CLIENT_TAG_PREFIX + "] prefix."); | ||
| } | ||
| } | ||
|
|
||
| clientTags.forEach((tagKey, tagValue) -> { | ||
| if (tagKey.length() > maxClientTagKeyValueLength) { | ||
| throw new ConfigException(CLIENT_TAG_PREFIX + tagKey, | ||
| tagValue, | ||
| "Key exceeds maximum length of " + maxClientTagKeyValueLength + "."); | ||
| } | ||
| if (tagValue.length() > maxClientTagKeyValueLength) { | ||
| throw new ConfigException(CLIENT_TAG_PREFIX + tagKey, | ||
| tagValue, | ||
| "Value exceeds max length of " + maxClientTagKeyValueLength + "."); | ||
| } | ||
| }); | ||
|
|
||
| return configUpdates; | ||
| } | ||
|
|
||
|
|
@@ -1238,6 +1319,7 @@ public Map<String, Object> getMainConsumerConfigs(final String groupId, final St | |
| consumerProps.put(REPLICATION_FACTOR_CONFIG, getInt(REPLICATION_FACTOR_CONFIG)); | ||
| consumerProps.put(APPLICATION_SERVER_CONFIG, getString(APPLICATION_SERVER_CONFIG)); | ||
| consumerProps.put(NUM_STANDBY_REPLICAS_CONFIG, getInt(NUM_STANDBY_REPLICAS_CONFIG)); | ||
| consumerProps.put(RACK_AWARE_ASSIGNMENT_TAGS_CONFIG, getList(RACK_AWARE_ASSIGNMENT_TAGS_CONFIG)); | ||
| consumerProps.put(ACCEPTABLE_RECOVERY_LAG_CONFIG, getLong(ACCEPTABLE_RECOVERY_LAG_CONFIG)); | ||
| consumerProps.put(MAX_WARMUP_REPLICAS_CONFIG, getInt(MAX_WARMUP_REPLICAS_CONFIG)); | ||
| consumerProps.put(PROBING_REBALANCE_INTERVAL_MS_CONFIG, getLong(PROBING_REBALANCE_INTERVAL_MS_CONFIG)); | ||
|
|
@@ -1389,6 +1471,23 @@ public Map<String, Object> getAdminConfigs(final String clientId) { | |
| return props; | ||
| } | ||
|
|
||
| /** | ||
| * Get the configured client tags set with {@link #CLIENT_TAG_PREFIX} prefix. | ||
| * @return Map of the client tags. | ||
| */ | ||
| @SuppressWarnings("WeakerAccess") | ||
| public Map<String, String> getClientTags() { | ||
| return originalsWithPrefix(CLIENT_TAG_PREFIX) | ||
| .entrySet() | ||
| .stream() | ||
| .collect( | ||
| Collectors.toMap( | ||
| Map.Entry::getKey, | ||
| tagEntry -> Objects.toString(tagEntry.getValue()) | ||
| ) | ||
| ); | ||
| } | ||
|
|
||
| private Map<String, Object> getClientPropsWithPrefix(final String prefix, | ||
| final Set<String> configNames) { | ||
| final Map<String, Object> props = clientProps(configNames, originals()); | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Sorry for the un-related changes :( happy to revert if it adds too much noise during the review.