-
Notifications
You must be signed in to change notification settings - Fork 15.4k
KAFKA-13603: Allow the empty active segment to have missing offset index during recovery #11345
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
Merged
Merged
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
ecb8692
Allow empty last segment to have missing offset index during recovery
ccding 9904830
Revert "Allow empty last segment to have missing offset index during …
ccding ac6e9cd
Merge branch 'trunk' into last
ccding a2c51d9
flush empty active segments
ccding 82913f0
add comment
ccding b915fe2
unit test
ccding 4df64d8
address comments
ccding 0f2f0a8
Merge branch 'trunk' into last
ccding c50bff2
flush at the right place
ccding 603627f
Merge branch 'trunk' into last
ccding 56d3f06
trigger test
ccding 425a7a7
address comments
ccding f345831
Merge branch 'trunk' into last
ccding 069ac5b
only do the inclusive flush in KRaft.close()
ccding 049c856
Merge branch 'trunk' into last
ccding 56d64cb
rename a bunch of variable/function names to address comments
ccding 7bb37b8
fix typo and purpose
ccding 40506eb
fix
ccding 6f70af3
do not print error if the missing index file is after the recovery point
ccding 23314ea
add log loader test
ccding d775f14
fix time stamp check
ccding 4d88092
fix comment
ccding 099cb42
fix log loader test
ccding 229a537
Merge branch 'trunk' into last
ccding 14239c0
trigger test
ccding 8b7e0c9
Merge branch 'trunk' into last
ccding 0c8e48b
Merge branch 'trunk' into last
ccding 25821db
address comments
ccding 47ba1d5
update comments and polish log messages
ccding 885db15
improve log message
ccding 5bb1a47
Merge branch 'trunk' into last
ccding e00906a
fix compile and improve log message
ccding bd21bb2
fix debug output
ccding 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
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
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.
I am wondering why the active segment will be missing the offset index file during a clean shutdown. When we load the segments during broker restart, we call resizeIndexes() on the last segment. This should trigger the creation of the offset index file, which will be flushed on broker shutdown.
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.
The sanityCheck is called before resizeIndexes.
It appears you are talking about we start the broker then immediately shut it down. In between the active segment may have been changed, and if the new one is empty, no index file is created.
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.
I am still trying to understand if the missing index is the result of a clean shutdown or a hard shutdown. When will roll a segment, the index on the new active segment is created lazily. However, during a clean shutdown, we force flush the active segment, which should trigger the creation of an empty index file because the following method is used in segment flush.
def offsetIndex: OffsetIndex = lazyOffsetIndex.getOn a hard shutdown, it's possible for the offset index to be missing. However, in that case, the offset index can be missing even when the log is not empty. So, I am wondering how common of an issue that we are fixing.
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.
@junrao: When the
UnifiedLogis flushed during clean shutdown, we flush theLocaLoguntil the logEndOffset. Here an empty active segment is not included in the list of candidate segments to be flushed. The reason is that duringLocalLog.flush(), theLogSegments.values(recoveryPoint, logEndOffset)call here does not select the empty active segment (doc), because, the logEndOffset would match the base offset of the empty active segment and thus get ommitted. So, prior to clean shutdown if the empty active segment's offset index was never created before, then, the offset index will not be created during clean shutdown because the empty active segment is never flushed.The above is shown in the following passing unit test:
This PR mainly fixes a logging issue in the code. For example, one situation where the issue happens more frequently is the following: Imagine there exists a topic with very low ingress traffic in some/all partitions. Imagine that for this topic the retention setting causes all existing segments to expire and get removed. In such a case, we roll the log to create an active segment. This ensures there is at least one segment remaining in the
LocalLogwhen the retention loop completes. However we don't create the offset index for the active segment until the first append operation. Now before the first append, if the Kafka cluster is rolled then we will see this false negative corruption error message during recovery.This PR fixes the logging problem by ignoring the absence of offset index for an empty active segment during recovery.
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.
@kowshik : Thanks for the great explanation. It makes sense to me now.
If we don't flush the only empty log segment during clean shutdown, we could lose the log segment file as well, which causes the replica to lose track of logEndOffset. I am wondering if we should force flush the empty log segment during clean shutdown too.
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.
Will
def flush(): Unit = flush(logEndOffset + 1)trigger flushing empty active segments every time we roll a segment, not only during shutdown?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.
@ccding When we roll a segment, we explicitly ensure to flush only the old segment. See this LOC.
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.
@kowshik : #8346 tries to avoid opening the index during close() when the index is not opened yet. This applies to existing segments on broker restart. For active segment, we typically need to open the index anyway. So, we probably don't need to optimize the rare case when it's empty. Plus, the danger of losing logEndOffset is a bigger concern than avoiding the cost of opening one index file.
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.
@junrao Sounds good to me. We can flush the active segment during clean shutdown. That's a very elegant way to handle this problem.
@ccding Would you like to update the PR with the approach proposed by @junrao?
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.
Updated. Please let me know if I misunderstood anything.