-
Notifications
You must be signed in to change notification settings - Fork 15.4k
KAFKA-15045: (KIP-924 pt. 15) Implement #defaultStandbyTaskAssignment and finish rack-aware standby optimization #16129
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
f51153c
56c990c
87dad64
597ae87
8eacaca
01d5f4d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,7 @@ | |
|
|
||
| import java.time.Instant; | ||
| import java.util.Optional; | ||
| import java.util.function.Function; | ||
| import org.apache.kafka.clients.admin.Admin; | ||
| import org.apache.kafka.clients.admin.ListOffsetsResult; | ||
| import org.apache.kafka.clients.admin.ListOffsetsResult.ListOffsetsResultInfo; | ||
|
|
@@ -555,18 +556,21 @@ private ApplicationState buildApplicationState(final TopologyMetadata topologyMe | |
|
|
||
| RackUtils.annotateTopicPartitionsWithRackInfo(cluster, internalTopicManager, allTopicPartitions); | ||
|
|
||
| final Set<TaskInfo> logicalTasks = logicalTaskIds.stream().map(taskId -> { | ||
| final Set<String> stateStoreNames = topologyMetadata | ||
| .stateStoreNameToSourceTopicsForTopology(taskId.topologyName()) | ||
| .keySet(); | ||
| final Set<TaskTopicPartition> topicPartitions = topicPartitionsForTask.get(taskId); | ||
| return new DefaultTaskInfo( | ||
| taskId, | ||
| !stateStoreNames.isEmpty(), | ||
| stateStoreNames, | ||
| topicPartitions | ||
| ); | ||
| }).collect(Collectors.toSet()); | ||
| final Map<TaskId, TaskInfo> logicalTasks = logicalTaskIds.stream().collect(Collectors.toMap( | ||
| Function.identity(), | ||
| taskId -> { | ||
| final Set<String> stateStoreNames = topologyMetadata | ||
| .stateStoreNameToSourceTopicsForTopology(taskId.topologyName()) | ||
|
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. Ah somehow I missed this before -- this is actually returning all the state stores for this topology, it's not specific to the taskId. This was an existing issue so we don't need to fix it in this PR, it can be addressed in a followup. It might be a bit complicated so I'll take a look at how we can get this info Would've caught this during testing since we definitely want tests with mixed stateless-and-stateful tasks, but still good to fix ASAP |
||
| .keySet(); | ||
| final Set<TaskTopicPartition> topicPartitions = topicPartitionsForTask.get(taskId); | ||
| return new DefaultTaskInfo( | ||
| taskId, | ||
| !stateStoreNames.isEmpty(), | ||
| stateStoreNames, | ||
| topicPartitions | ||
| ); | ||
| } | ||
| )); | ||
|
|
||
| return new DefaultApplicationState( | ||
| assignmentConfigs.toPublicAssignmentConfigs(), | ||
|
|
@@ -728,12 +732,12 @@ private void checkAllPartitions(final Set<String> allSourceTopics, | |
| * populate the stateful tasks that have been assigned to the clients | ||
| */ | ||
| private UserTaskAssignmentListener assignTasksToClients(final Cluster fullMetadata, | ||
| final Set<String> allSourceTopics, | ||
| final Map<Subtopology, TopicsInfo> topicGroups, | ||
| final Map<UUID, ClientMetadata> clientMetadataMap, | ||
| final Map<TaskId, Set<TopicPartition>> partitionsForTask, | ||
| final Map<UUID, Map<String, Optional<String>>> racksForProcessConsumer, | ||
| final Set<TaskId> statefulTasks) { | ||
| final Set<String> allSourceTopics, | ||
| final Map<Subtopology, TopicsInfo> topicGroups, | ||
| final Map<UUID, ClientMetadata> clientMetadataMap, | ||
| final Map<TaskId, Set<TopicPartition>> partitionsForTask, | ||
| final Map<UUID, Map<String, Optional<String>>> racksForProcessConsumer, | ||
| final Set<TaskId> statefulTasks) { | ||
| if (!statefulTasks.isEmpty()) { | ||
| throw new TaskAssignmentException("The stateful tasks should not be populated before assigning tasks to clients"); | ||
| } | ||
|
|
@@ -775,7 +779,7 @@ private UserTaskAssignmentListener assignTasksToClients(final Cluster fullMetada | |
|
|
||
| final Optional<org.apache.kafka.streams.processor.assignment.TaskAssignor> userTaskAssignor = | ||
| userTaskAssignorSupplier.get(); | ||
| UserTaskAssignmentListener userTaskAssignmentListener = (GroupAssignment assignment, GroupSubscription subscription) -> { }; | ||
| final UserTaskAssignmentListener userTaskAssignmentListener; | ||
| if (userTaskAssignor.isPresent()) { | ||
| final ApplicationState applicationState = buildApplicationState( | ||
| taskManager.topologyMetadata(), | ||
|
|
@@ -785,12 +789,11 @@ private UserTaskAssignmentListener assignTasksToClients(final Cluster fullMetada | |
| ); | ||
| final org.apache.kafka.streams.processor.assignment.TaskAssignor assignor = userTaskAssignor.get(); | ||
| final TaskAssignment taskAssignment = assignor.assign(applicationState); | ||
| processStreamsPartitionAssignment(clientMetadataMap, taskAssignment); | ||
| final AssignmentError assignmentError = validateTaskAssignment(applicationState, taskAssignment); | ||
| userTaskAssignmentListener = (GroupAssignment assignment, GroupSubscription subscription) -> { | ||
| assignor.onAssignmentComputed(assignment, subscription, assignmentError); | ||
| }; | ||
| processStreamsPartitionAssignment(clientMetadataMap, taskAssignment); | ||
| userTaskAssignmentListener = (assignment, subscription) -> assignor.onAssignmentComputed(assignment, subscription, assignmentError); | ||
| } else { | ||
| userTaskAssignmentListener = (assignment, subscription) -> { }; | ||
| final TaskAssignor taskAssignor = createTaskAssignor(lagComputationSuccessful); | ||
| final RackAwareTaskAssignor rackAwareTaskAssignor = new RackAwareTaskAssignor( | ||
| fullMetadata, | ||
|
|
@@ -1564,7 +1567,7 @@ private AssignmentError validateTaskAssignment(final ApplicationState applicatio | |
| final Map<TaskId, ProcessId> standbyTasksInOutput = new HashMap<>(); | ||
| for (final KafkaStreamsAssignment assignment : assignments) { | ||
| final Set<TaskId> tasksForAssignment = new HashSet<>(); | ||
| for (final KafkaStreamsAssignment.AssignedTask task : assignment.assignment()) { | ||
| for (final KafkaStreamsAssignment.AssignedTask task : assignment.tasks().values()) { | ||
| if (activeTasksInOutput.containsKey(task.id()) && task.type() == KafkaStreamsAssignment.AssignedTask.Type.ACTIVE) { | ||
| log.error("Assignment is invalid: active task {} was assigned to multiple KafkaStreams clients: {} and {}", | ||
| task.id(), assignment.processId().id(), activeTasksInOutput.get(task.id()).id()); | ||
|
|
@@ -1614,7 +1617,7 @@ private AssignmentError validateTaskAssignment(final ApplicationState applicatio | |
|
|
||
| final Set<TaskId> taskIdsInInput = applicationState.allTasks().keySet(); | ||
| for (final KafkaStreamsAssignment assignment : assignments) { | ||
| for (final KafkaStreamsAssignment.AssignedTask task : assignment.assignment()) { | ||
| for (final KafkaStreamsAssignment.AssignedTask task : assignment.tasks().values()) { | ||
| if (!taskIdsInInput.contains(task.id())) { | ||
| log.error("Assignment is invalid: task {} assigned to KafkaStreams client {} was unknown", | ||
| task.id(), assignment.processId().id()); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.