-
Notifications
You must be signed in to change notification settings - Fork 15.4k
KAFKA-20711: Measure restore-remaining-records in offset slots #22614
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
base: trunk
Are you sure you want to change the base?
Changes from all commits
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 |
|---|---|---|
|
|
@@ -141,6 +141,9 @@ static class ChangelogMetadata { | |
|
|
||
| private long restoreStartTimeNs; | ||
|
|
||
| // the consumer position at which restoration started, so progress can be measured in offset slots | ||
| private long restoreStartOffset; | ||
|
|
||
| private ChangelogMetadata(final StateStoreMetadata storeMetadata, final ProcessorStateManager stateManager) { | ||
| this.changelogState = ChangelogState.REGISTERED; | ||
| this.storeMetadata = storeMetadata; | ||
|
|
@@ -668,6 +671,8 @@ private int restoreChangelog(final Task task, final ChangelogMetadata changelogM | |
|
|
||
| if (numRecords != 0) { | ||
| final List<ConsumerRecord<byte[], byte[]>> records = changelogMetadata.bufferedRecords.subList(0, numRecords); | ||
| // where restoration had reached before this batch; null until the first batch is restored | ||
| final Long offsetBeforeRestore = storeMetadata.offset(); | ||
| final OptionalLong optionalLag = restoreConsumer.currentLag(partition); | ||
| stateManager.restore(storeMetadata, records, optionalLag); | ||
|
|
||
|
|
@@ -680,9 +685,9 @@ private int restoreChangelog(final Task task, final ChangelogMetadata changelogM | |
| changelogMetadata.bufferedRecords.clear(); | ||
| } | ||
|
|
||
| task.recordRestoration(time, numRecords, false); | ||
|
|
||
| final Long currentOffset = storeMetadata.offset(); | ||
| recordRestorationProgress(task, changelogMetadata, numRecords, offsetBeforeRestore, currentOffset); | ||
|
|
||
| log.trace("Restored {} records from changelog {} to store {}, end offset is {}, current offset is {}", | ||
| numRecords, partition, storeName, recordEndOffset(changelogMetadata.restoreEndOffset), currentOffset); | ||
|
|
||
|
|
@@ -710,6 +715,10 @@ private int restoreChangelog(final Task task, final ChangelogMetadata changelogM | |
| log.info("Finished restoring changelog {} to store {} with a total number of {} records", | ||
| partition, storeName, changelogMetadata.totalRestored); | ||
|
|
||
| // account for any offset slots past the last restored record (e.g. trailing transaction | ||
| // markers) so the remaining-records metric reaches exactly zero on completion | ||
| recordRestorationProgress(task, changelogMetadata, 0, storeMetadata.offset(), changelogMetadata.restoreEndOffset - 1); | ||
|
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. Why
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. Base on my other comment, wondering if we would need to to Or change |
||
|
|
||
| changelogMetadata.transitTo(ChangelogState.COMPLETED); | ||
| pauseChangelogsFromRestoreConsumer(Collections.singleton(partition)); | ||
| if (storeMetadata.store() instanceof MeteredStateStore) { | ||
|
|
@@ -730,6 +739,23 @@ private int restoreChangelog(final Task task, final ChangelogMetadata changelogM | |
| return numRecords; | ||
| } | ||
|
|
||
| /** | ||
| * Record restoration progress: restore-total/restore-rate advance by the records restored | ||
| * ({@code numRecords}), while the remaining-records metric is decremented by the offset slots | ||
| * between {@code previousOffset} (or {@code restoreStartOffset} if null) and {@code restoredToOffset}. | ||
| * Measuring the latter in offset slots accounts for offsets the restore consumer never returns | ||
| * (transaction markers, compacted records) so it reaches exactly zero on completion. | ||
| */ | ||
| private void recordRestorationProgress(final Task task, | ||
| final ChangelogMetadata changelogMetadata, | ||
| final long numRecords, | ||
| final Long previousOffset, | ||
| final long restoredToOffset) { | ||
| final long restoredFrom = previousOffset == null ? changelogMetadata.restoreStartOffset - 1 : previousOffset; | ||
|
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. Why do we need
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. Should this be |
||
| final long numOffsets = Math.max(restoredToOffset - restoredFrom, 0L); | ||
|
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. Could the |
||
| task.recordRestoration(time, numRecords, numOffsets, false); | ||
| } | ||
|
|
||
| private Set<Task> getTasksFromPartitions(final Map<TaskId, Task> tasks, | ||
| final Set<TopicPartition> partitions) { | ||
| final Set<Task> result = new HashSet<>(); | ||
|
|
@@ -1033,6 +1059,8 @@ private void prepareChangelogs(final Map<TaskId, Task> tasks, | |
| throw new StreamsException("Restore consumer get unexpected error trying to get the position " + | ||
| " of " + partition, e); | ||
| } | ||
| // remember where restoration began so progress can be measured in offset slots | ||
| changelogMetadata.restoreStartOffset = startOffset; | ||
| if (changelogMetadata.stateManager.taskType() == Task.TaskType.ACTIVE) { | ||
| try { | ||
| stateRestoreListener.onRestoreStart(partition, storeName, startOffset, changelogMetadata.restoreEndOffset); | ||
|
|
@@ -1045,8 +1073,8 @@ private void prepareChangelogs(final Map<TaskId, Task> tasks, | |
| // if the log is truncated between when we get the log end offset and when we get the | ||
| // consumer position, then it's possible that the difference become negative and there's actually | ||
| // no records to restore; in this case we just initialize the sensor to zero | ||
| final long recordsToRestore = Math.max(changelogMetadata.restoreEndOffset - startOffset, 0L); | ||
| task.recordRestoration(time, recordsToRestore, true); | ||
| final long offsetsToRestore = Math.max(changelogMetadata.restoreEndOffset - startOffset, 0L); | ||
| task.recordRestoration(time, 0, offsetsToRestore, true); | ||
| changelogMetadata.restoreStartTimeNs = time.nanoseconds(); | ||
| } else if (changelogMetadata.stateManager.taskType() == TaskType.STANDBY) { | ||
| try { | ||
|
|
||
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.
Do we need to add
+1here (depending what we really want to track, or how to do the math).storeMetadata.offset()return the offset of the last restored record, to the "restore position" is one larger.