-
Notifications
You must be signed in to change notification settings - Fork 15.4k
MINOR: Improve log4j for per-consumer assignment #8997
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 2 commits
763aa52
3ae2df4
37c57d5
be0d18c
a3e5746
3c4885e
d7e54dd
2a0c09e
581980b
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 |
|---|---|---|
|
|
@@ -120,8 +120,8 @@ public int hashCode() { | |
| private static class ClientMetadata { | ||
|
|
||
| private final HostInfo hostInfo; | ||
| private final SortedSet<String> consumers; | ||
| private final ClientState state; | ||
| private final SortedSet<String> consumers; | ||
|
|
||
| ClientMetadata(final String endPoint) { | ||
|
|
||
|
|
@@ -725,8 +725,10 @@ private boolean assignTasksToClients(final Set<String> allSourceTopics, | |
| statefulTasks, | ||
| assignmentConfigs); | ||
|
|
||
| log.info("Assigned tasks to clients as {}{}.", | ||
| Utils.NL, clientStates.entrySet().stream().map(Map.Entry::toString).collect(Collectors.joining(Utils.NL))); | ||
| log.info("Assigned tasks to clients as: {}{}.", Utils.NL, | ||
| clientStates.entrySet().stream() | ||
| .map(entry -> entry.getKey() + "=" + entry.getValue().currentAssignment()) | ||
| .collect(Collectors.joining(Utils.NL))); | ||
|
|
||
| return probingRebalanceNeeded; | ||
| } | ||
|
|
@@ -931,7 +933,9 @@ private Map<String, Assignment> computeNewAssignment(final Map<UUID, ClientMetad | |
| state | ||
| ); | ||
|
|
||
| // Arbitrarily choose the leader's client to be responsible for triggering the probing rebalance | ||
| // Arbitrarily choose the leader's client to be responsible for triggering the probing rebalance, | ||
| // note once we pick the first consumer of the processor to trigger probing rebalance, other threads | ||
|
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. super nit: processor --> process (or bet yet, 'client') |
||
| // would not set to trigger any more. | ||
| final boolean encodeNextProbingRebalanceTime = shouldTriggerProbingRebalance && clientId.equals(taskManager.processId()); | ||
|
|
||
| final boolean tasksRevoked = addClientAssignments( | ||
|
|
@@ -952,6 +956,18 @@ private Map<String, Assignment> computeNewAssignment(final Map<UUID, ClientMetad | |
| rebalanceRequired = true; | ||
| log.debug("Requested client {} to schedule a followup rebalance", clientId); | ||
| } | ||
|
|
||
| log.info("Client {} per-consumer assignment:\n" + | ||
| "\tprev owned active {}\n" + | ||
|
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 alignment looks weird. |
||
| "\tprev owned standby {}\n" + | ||
| "\tassigned active {}\n" + | ||
| "\trevoking active {}" + | ||
| "\tassigned standby {}\n", clientId, | ||
| clientMetadata.state.prevOwnedActiveByConsumer(), | ||
| clientMetadata.state.prevOwnedStandbyByConsumer(), | ||
| clientMetadata.state.assignedActiveByConsumer(), | ||
| clientMetadata.state.revokingActiveByConsumer(), | ||
| clientMetadata.state.assignedStandbyByConsumer()); | ||
| } | ||
|
|
||
| if (rebalanceRequired) { | ||
|
|
@@ -1023,14 +1039,15 @@ private boolean addClientAssignments(final Map<String, Assignment> assignment, | |
|
|
||
| if (!activeTasksRemovedPendingRevokation.isEmpty()) { | ||
| // TODO: once KAFKA-10078 is resolved we can leave it to the client to trigger this rebalance | ||
| log.info("Requesting followup rebalance be scheduled immediately due to tasks changing ownership."); | ||
| log.info("Requesting {} followup rebalance be scheduled immediately due to tasks changing ownership.", consumer); | ||
| info.setNextRebalanceTime(0L); | ||
| followupRebalanceRequiredForRevokedTasks = true; | ||
| // Don't bother to schedule a probing rebalance if an immediate one is already scheduled | ||
| shouldEncodeProbingRebalance = false; | ||
| } else if (shouldEncodeProbingRebalance) { | ||
| final long nextRebalanceTimeMs = time.milliseconds() + probingRebalanceIntervalMs(); | ||
| log.info("Requesting followup rebalance be scheduled for {} ms to probe for caught-up replica tasks.", nextRebalanceTimeMs); | ||
| log.info("Requesting {} followup rebalance be scheduled for {} ms to probe for caught-up replica tasks.", | ||
| consumer, nextRebalanceTimeMs); | ||
| info.setNextRebalanceTime(nextRebalanceTimeMs); | ||
| shouldEncodeProbingRebalance = false; | ||
| } | ||
|
|
@@ -1061,8 +1078,11 @@ private Set<TaskId> populateActiveTaskAndPartitionsLists(final List<TopicPartiti | |
| final List<AssignedPartition> assignedPartitions = new ArrayList<>(); | ||
| final Set<TaskId> removedActiveTasks = new TreeSet<>(); | ||
|
|
||
| // Build up list of all assigned partition-task pairs | ||
| for (final TaskId taskId : activeTasksForConsumer) { | ||
| // Populate the consumer for assigned tasks without considering revocation, | ||
| // this is for debugging purposes only | ||
| clientState.assignActiveToConsumer(taskId, consumer); | ||
|
|
||
| final List<AssignedPartition> assignedPartitionsForTask = new ArrayList<>(); | ||
| for (final TopicPartition partition : partitionsForTask.get(taskId)) { | ||
| final String oldOwner = clientState.previousOwnerForPartition(partition); | ||
|
|
@@ -1078,6 +1098,8 @@ private Set<TaskId> populateActiveTaskAndPartitionsLists(final List<TopicPartiti | |
| ); | ||
| removedActiveTasks.add(taskId); | ||
|
|
||
| clientState.revokeActiveFromConsumer(taskId, consumer); | ||
|
abbccdda marked this conversation as resolved.
|
||
|
|
||
| // Clear the assigned partitions list for this task if any partition can not safely be assigned, | ||
| // so as not to encode a partial task | ||
| assignedPartitionsForTask.clear(); | ||
|
|
@@ -1113,6 +1135,7 @@ private Map<TaskId, Set<TopicPartition>> buildStandbyTaskMap(final String consum | |
| final ClientState clientState) { | ||
| final Map<TaskId, Set<TopicPartition>> standbyTaskMap = new HashMap<>(); | ||
| for (final TaskId task : standbys) { | ||
| clientState.assignStandbyToConsumer(task, consumer); | ||
|
abbccdda marked this conversation as resolved.
|
||
| standbyTaskMap.put(task, partitionsForTask.get(task)); | ||
| } | ||
| for (final TaskId task : tasksRevoked) { | ||
|
|
@@ -1121,6 +1144,8 @@ private Map<TaskId, Set<TopicPartition>> buildStandbyTaskMap(final String consum | |
| task, | ||
| consumer | ||
| ); | ||
|
|
||
| clientState.assignStandbyToConsumer(task, consumer); | ||
| standbyTaskMap.put(task, partitionsForTask.get(task)); | ||
|
|
||
| // This has no effect on the assignment, as we'll never consult the ClientState again, but | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,19 +16,20 @@ | |
| */ | ||
| package org.apache.kafka.streams.processor.internals.assignment; | ||
|
|
||
| import java.util.stream.Collectors; | ||
| import org.apache.kafka.common.TopicPartition; | ||
| import org.apache.kafka.streams.processor.TaskId; | ||
| import org.apache.kafka.streams.processor.internals.Task; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Collection; | ||
| import java.util.Comparator; | ||
| import java.util.HashSet; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.Set; | ||
| import java.util.SortedMap; | ||
| import java.util.stream.Collectors; | ||
| import java.util.TreeMap; | ||
| import java.util.TreeSet; | ||
| import java.util.UUID; | ||
|
|
@@ -50,10 +51,15 @@ public class ClientState { | |
| private final Set<TaskId> prevStandbyTasks; | ||
|
|
||
| private final Map<String, Set<TaskId>> consumerToPreviousStatefulTaskIds; | ||
| private final Map<String, List<TaskId>> consumerToPreviousActiveTaskIds; | ||
| private final Map<String, List<TaskId>> consumerToAssignedActiveTaskIds; | ||
| private final Map<String, List<TaskId>> consumerToAssignedStandbyTaskIds; | ||
| private final Map<String, List<TaskId>> consumerToRevokingActiveTaskIds; | ||
| private final Map<TopicPartition, String> ownedPartitions; | ||
| private final Map<TaskId, Long> taskOffsetSums; // contains only stateful tasks we previously owned | ||
| private final Map<TaskId, Long> taskLagTotals; // contains lag for all stateful tasks in the app topology | ||
|
|
||
|
|
||
| private int capacity; | ||
|
|
||
| public ClientState() { | ||
|
|
@@ -66,32 +72,17 @@ public ClientState() { | |
| prevActiveTasks = new TreeSet<>(); | ||
| prevStandbyTasks = new TreeSet<>(); | ||
| consumerToPreviousStatefulTaskIds = new TreeMap<>(); | ||
| consumerToPreviousActiveTaskIds = new TreeMap<>(); | ||
|
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: we could initialize on the parameter definition. |
||
| consumerToAssignedActiveTaskIds = new TreeMap<>(); | ||
| consumerToAssignedStandbyTaskIds = new TreeMap<>(); | ||
| consumerToRevokingActiveTaskIds = new TreeMap<>(); | ||
| ownedPartitions = new TreeMap<>(TOPIC_PARTITION_COMPARATOR); | ||
| taskOffsetSums = new TreeMap<>(); | ||
| taskLagTotals = new TreeMap<>(); | ||
| this.capacity = capacity; | ||
| } | ||
|
|
||
| private ClientState(final Set<TaskId> activeTasks, | ||
|
abbccdda marked this conversation as resolved.
|
||
| final Set<TaskId> standbyTasks, | ||
| final Set<TaskId> prevActiveTasks, | ||
| final Set<TaskId> prevStandbyTasks, | ||
| final Map<String, Set<TaskId>> consumerToPreviousStatefulTaskIds, | ||
| final SortedMap<TopicPartition, String> ownedPartitions, | ||
| final Map<TaskId, Long> taskOffsetSums, | ||
| final Map<TaskId, Long> taskLagTotals, | ||
| final int capacity) { | ||
| this.activeTasks = activeTasks; | ||
| this.standbyTasks = standbyTasks; | ||
| this.prevActiveTasks = prevActiveTasks; | ||
| this.prevStandbyTasks = prevStandbyTasks; | ||
| this.consumerToPreviousStatefulTaskIds = consumerToPreviousStatefulTaskIds; | ||
| this.ownedPartitions = ownedPartitions; | ||
| this.taskOffsetSums = taskOffsetSums; | ||
| this.taskLagTotals = taskLagTotals; | ||
| this.capacity = capacity; | ||
| } | ||
|
|
||
| // For testing only | ||
| public ClientState(final Set<TaskId> previousActiveTasks, | ||
| final Set<TaskId> previousStandbyTasks, | ||
| final Map<TaskId, Long> taskLagTotals, | ||
|
|
@@ -101,27 +92,16 @@ public ClientState(final Set<TaskId> previousActiveTasks, | |
| prevActiveTasks = unmodifiableSet(new TreeSet<>(previousActiveTasks)); | ||
| prevStandbyTasks = unmodifiableSet(new TreeSet<>(previousStandbyTasks)); | ||
| consumerToPreviousStatefulTaskIds = new TreeMap<>(); | ||
| consumerToPreviousActiveTaskIds = new TreeMap<>(); | ||
| consumerToAssignedActiveTaskIds = new TreeMap<>(); | ||
| consumerToAssignedStandbyTaskIds = new TreeMap<>(); | ||
| consumerToRevokingActiveTaskIds = new TreeMap<>(); | ||
| ownedPartitions = new TreeMap<>(TOPIC_PARTITION_COMPARATOR); | ||
| taskOffsetSums = emptyMap(); | ||
| this.taskLagTotals = unmodifiableMap(taskLagTotals); | ||
| this.capacity = capacity; | ||
| } | ||
|
|
||
| public ClientState copy() { | ||
| final TreeMap<TopicPartition, String> newOwnedPartitions = new TreeMap<>(TOPIC_PARTITION_COMPARATOR); | ||
| newOwnedPartitions.putAll(ownedPartitions); | ||
| return new ClientState( | ||
| new TreeSet<>(activeTasks), | ||
| new TreeSet<>(standbyTasks), | ||
| new TreeSet<>(prevActiveTasks), | ||
| new TreeSet<>(prevStandbyTasks), | ||
| new TreeMap<>(consumerToPreviousStatefulTaskIds), | ||
| newOwnedPartitions, | ||
| new TreeMap<>(taskOffsetSums), | ||
| new TreeMap<>(taskLagTotals), | ||
| capacity); | ||
| } | ||
|
|
||
| int capacity() { | ||
| return capacity; | ||
| } | ||
|
|
@@ -150,6 +130,48 @@ public void assignActiveTasks(final Collection<TaskId> tasks) { | |
| activeTasks.addAll(tasks); | ||
| } | ||
|
|
||
| public void assignActiveToConsumer(final TaskId task, final String consumer) { | ||
| consumerToAssignedActiveTaskIds.getOrDefault(consumer, new ArrayList<>()).add(task); | ||
| } | ||
|
|
||
| public void assignStandbyToConsumer(final TaskId task, final String consumer) { | ||
| consumerToAssignedStandbyTaskIds.getOrDefault(consumer, new ArrayList<>()).add(task); | ||
| } | ||
|
|
||
| public void revokeActiveFromConsumer(final TaskId task, final String consumer) { | ||
| consumerToRevokingActiveTaskIds.getOrDefault(consumer, new ArrayList<>()).add(task); | ||
| } | ||
|
|
||
| public Map<String, List<TaskId>> prevOwnedActiveByConsumer() { | ||
| return consumerToPreviousActiveTaskIds; | ||
| } | ||
|
|
||
| public Map<String, List<TaskId>> prevOwnedStandbyByConsumer() { | ||
| // standbys are just those stateful tasks minus active tasks | ||
| final Map<String, List<TaskId>> consumerToPreviousStandbyTaskIds = new TreeMap<>(); | ||
|
|
||
| for (final Map.Entry<String, Set<TaskId>> entry: consumerToPreviousStatefulTaskIds.entrySet()) { | ||
| final List<TaskId> standbyTaskIds = new ArrayList<>(entry.getValue()); | ||
| if (consumerToPreviousActiveTaskIds.containsKey(entry.getKey())) | ||
| standbyTaskIds.removeAll(consumerToPreviousActiveTaskIds.get(entry.getKey())); | ||
| consumerToPreviousStandbyTaskIds.put(entry.getKey(), standbyTaskIds); | ||
| } | ||
|
|
||
| return consumerToPreviousStandbyTaskIds; | ||
| } | ||
|
|
||
| public Map<String, List<TaskId>> assignedActiveByConsumer() { | ||
| return consumerToAssignedActiveTaskIds; | ||
| } | ||
|
|
||
| public Map<String, List<TaskId>> revokingActiveByConsumer() { | ||
| return consumerToRevokingActiveTaskIds; | ||
| } | ||
|
|
||
| public Map<String, List<TaskId>> assignedStandbyByConsumer() { | ||
| return consumerToAssignedStandbyTaskIds; | ||
| } | ||
|
|
||
| public void assignActive(final TaskId task) { | ||
| assertNotAssigned(task); | ||
| activeTasks.add(task); | ||
|
|
@@ -345,13 +367,17 @@ boolean hasMoreAvailableCapacityThan(final ClientState other) { | |
| } | ||
| } | ||
|
|
||
| public String currentAssignment() { | ||
| return "[activeTasks: (" + activeTasks + | ||
| ") standbyTasks: (" + standbyTasks + ")]"; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "[activeTasks: (" + activeTasks + | ||
| ") standbyTasks: (" + standbyTasks + | ||
| ") prevActiveTasks: (" + prevActiveTasks + | ||
| ") prevStandbyTasks: (" + prevStandbyTasks + | ||
| ") prevOwnedPartitionsByConsumerId: (" + ownedPartitions.keySet() + | ||
| ") changelogOffsetTotalsByTask: (" + taskOffsetSums.entrySet() + | ||
| ") taskLagTotals: (" + taskLagTotals.entrySet() + | ||
| ") capacity: " + capacity + | ||
|
|
@@ -373,6 +399,7 @@ private void initializePrevActiveTasksFromOwnedPartitions(final Map<TopicPartiti | |
| final TaskId task = taskForPartitionMap.get(tp); | ||
| if (task != null) { | ||
| addPreviousActiveTask(task); | ||
| consumerToPreviousActiveTaskIds.getOrDefault(partitionEntry.getValue(), new ArrayList<>()).add(task); | ||
| } else { | ||
| LOG.error("No task found for topic partition {}", tp); | ||
| } | ||
|
|
||
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.
This is unnecessarily verbose, plus part of it is replaced by line 960 below, so I trimmed a bit here.
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.
Thanks, this one has always made my head spin when reading the logs