-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
kvserver: clean up replica unquiescence #105041
kvserver: clean up replica unquiescence #105041
Conversation
@tbg @pavelkalinnikov Would like some scrutiny of the "only wake leader when unquiescing a follower" commit here. It seems problematic and unnecessary that we submit a proposal when the leader wakes itself, but it's possible that we've come to rely implicitly on this logic.
|
3df693c
to
df4b6bc
Compare
0ea89a1
to
6be9e48
Compare
Saw the same problem with |
|
c749770
to
7afc8a0
Compare
7afc8a0
to
24459ca
Compare
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.
Nice, thanks.
The leader won't quiesce if followers aren't caught up. Epic: none Release note: None
This patch merges `maybeUnquiesceAndWakeLeaderLocked()` into `maybeUnquiesceWithOptionsLocked()`, using a separate parameter to wake the leader. Care is taken to make this purely mechanical, with no logical changes at all. Epic: none Release note: None
This patch merges `maybeUnquiesceWithOptionsLocked()` into `maybeUnquiesceLocked()`, requiring callers to always specify options. The subtlety around unquiescence, and few call sites, makes it beneficial to be explicit. This is a purely mechanical change, with no logical changes. A couple of tests have been changed to now wake the leader when unquiescing, but this has no bearing on the tests. Epic: none Release note: None
Previously, `Replica.lastUpdateTimes` was updated whenever a replica unquiesced without attempting to wake the leader. However, this had two flaws: a leader could fail to call it if it hit a code path where it did attempt to wake the leader (even if it was leader itself), e.g. by returning `true` from `withRaftGroup()`, and it could also be called on a follower where it would have no effect. This patch instead updates it when unquiescing the leader, regardless of unquiesce options. Epic: none Release note: None
Previously, any replica would wake the leader when unquiescing, if requested by the caller. However, this could cause the leader to propose an empty command to wake itself, which commonly happens in `handleRaftReady()` via `withRaftGroupLocked()`. This appears unnecessary, and likely causes a large amount of Raft proposals with ranges that frequently (un)quiesce. This patch instead only attempts to wake the leader from followers. Epic: none Release note: None
We should wake the leader before campaigning when unquiescing, since we won't send the proposal in the candidate state and thus won't give the leader a chance to assert leadership if we're wrong about it being dead. Epic: none Release note: None
This patch changes a couple of `maybeUnquiesce()` call sites to not attempt to campaign when we know the replica must already be the leader. Epic: none Release note: None
24459ca
to
50d7264
Compare
if wakeLeader { | ||
// Propose an empty command which will wake the leader. | ||
if log.V(3) { | ||
log.Infof(ctx, "waking %d leader", r.RangeID) |
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.
How about "r%d" instead of "%d". It's easier to search by "rNNN" in logs when investigating, this avoids false positives.
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 was following the convention of the existing log messages here, didn't particularly feel like updating a bunch of log messages. But I can do a pass if there aren't that many to update.
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.
Tacked on a commit.
@@ -495,15 +495,7 @@ func (r *Replica) GetQueueLastProcessed(ctx context.Context, queue string) (hlc. | |||
} | |||
|
|||
func (r *Replica) MaybeUnquiesce() bool { |
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 semantics of MaybeUnquiesce
changed. Were there any callers who wanted the old behaviour (wakeLeader=mayCampaign=false)?
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 tests don't care -- explained in the commit message:
A couple of tests have been changed to now wake the leader when unquiescing, but this has no bearing on the tests.
In case it wasn't clear, this is a test-only file, helpers_test.go
.
|
||
if wakeLeader { | ||
} else if st.RaftState == raft.StateFollower && wakeLeader { |
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.
Why not in StateCandidate
? Waking the leader doesn't make sense because the candidate "doesn't know" the leader?
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.
Correct, a candidate has no leader, and won't send proposals.
@@ -705,7 +705,7 @@ func (s *Store) nodeIsLiveCallback(l livenesspb.Liveness) { | |||
lagging := r.mu.laggingFollowersOnQuiesce | |||
r.mu.RUnlock() | |||
if quiescent && lagging.MemberStale(l) { | |||
r.maybeUnquiesce(false /* wakeLeader */, true /* mayCampaign */) | |||
r.maybeUnquiesce(false /* wakeLeader */, false /* mayCampaign */) // already leader |
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.
Why do we know we're already leader 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.
Because laggingFollowersOnQuiesce
is only non-nil on the leader. Conceptually, only the leader keeps track of lagging followers, because only leaders have followers.
Epic: none Release note: None
TFTRs! bors r+ |
Build succeeded: |
kvserver: remove stale
maybeQuiesce
TODOThe leader won't quiesce if followers aren't caught up.
kvserver: remove
maybeUnquiesceAndWakeLeaderLocked
This patch merges
maybeUnquiesceAndWakeLeaderLocked()
intomaybeUnquiesceWithOptionsLocked()
, using a separate parameter to wake the leader. Care is taken to make this purely mechanical, with no logical changes at all.kvserver: remove
maybeUnquiesceWithOptionsLocked
This patch merges
maybeUnquiesceWithOptionsLocked()
intomaybeUnquiesceLocked()
, requiring callers to always specify options. The subtlety around unquiescence, and few call sites, makes it beneficial to be explicit.This is a purely mechanical change, with no logical changes. A couple of tests have been changed to now wake the leader when unquiescing, but this has no bearing on the tests.
kvserver: set last update times on leader unquiesce
Previously,
Replica.lastUpdateTimes
was updated whenever a replica unquiesced without attempting to wake the leader. However, this had two flaws: a leader could fail to call it if it hit a code path where it did attempt to wake the leader (even if it was leader itself), e.g. by returningtrue
fromwithRaftGroup()
, and it could also be called on a follower where it would have no effect.This patch instead updates it when unquiescing the leader, regardless of unquiesce options.
kvserver: only wake leader when unquiescing a follower
Previously, any replica would wake the leader when unquiescing, if requested by the caller. However, this could cause the leader to propose an empty command to wake itself, which commonly happens in
handleRaftReady()
viawithRaftGroupLocked()
. This appears unnecessary, and likely causes a large amount of Raft proposals with ranges that frequently (un)quiesce.This patch instead only attempts to wake the leader from followers.
kvserver: wake leader before campaigning when unquiescing
We should wake the leader before campaigning when unquiescing, since we won't send the proposal in the candidate state and thus won't give the leader a chance to assert leadership if we're wrong about it being dead.
kvserver: omit unnecessary campaign checks on leader unquiescence
This patch changes a couple of
maybeUnquiesce()
call sites to not attempt to campaign when we know the replica must already be the leader.Epic: none
Release note: None