forked from cockroachdb/cockroach
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
kvserver,kvflowcontrol: integrate flow control
Part of cockroachdb#95563. This PR integrates various kvflowcontrol components into the critical path for replication traffic. It does so by introducing two "integration interfaces" in the kvserver package to intercept various points of a replica's lifecycle, using it to manage the underlying replication streams and flow tokens. The integration is mediated through two cluster settings: - kvadmission.flow_control.enabled This is a top-level kill-switch to revert to pre-kvflowcontrol behavior where follower writes unilaterally deducted IO tokens without blocking. - kvadmission.flow_control.mode It can take on one of three settings, each exercising the flow control machinery to varying degrees. - apply_to_elastic Only applies admission delays to elastic traffic. - apply_to_all Applies admission delays to {regular,elastic} traffic. When the mode is changed, we simply admit all waiting requests. This risks possibly over-admitting work, but that's ok -- we assume these mode changes are rare events and done under supervision. These settings are hooked into in the kvadmission and kvflowcontroller packages. As for the actual integration interfaces in kvserver, they are: - replicaFlowControlIntegration: used to integrate with replication flow control. It's intercepts various points in a replica's lifecycle, like it acquiring raft leadership or losing it, or its raft membership changing, etc. Accessing it requires Replica.mu to be held, exclusively (this is asserted on in the canonical implementation). type replicaFlowControlIntegration interface { handle() (kvflowcontrol.Handle, bool) onBecameLeader(context.Context) onBecameFollower(context.Context) onDescChanged(context.Context) onFollowersPaused(context.Context) onReplicaDestroyed(context.Context) onProposalQuotaUpdated(context.Context) } - replicaForFlowControl abstracts the interface of an individual Replica, as needed by replicaFlowControlIntegration. type replicaForFlowControl interface { assertLocked() annotateCtx(context.Context) context.Context getTenantID() roachpb.TenantID getReplicaID() roachpb.ReplicaID getRangeID() roachpb.RangeID getDescriptor() *roachpb.RangeDescriptor pausedFollowers() map[roachpb.ReplicaID]struct{} isFollowerActive(context.Context, roachpb.ReplicaID) bool appliedLogPosition() kvflowcontrolpb.RaftLogPosition withReplicaProgress(f func(roachpb.ReplicaID, rafttracker.Progress)) } Release note: None
- Loading branch information
1 parent
4241f6b
commit 8029f27
Showing
53 changed files
with
1,667 additions
and
128 deletions.
There are no files selected for viewing
This file contains 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 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 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 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 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
// Copyright 2023 The Cockroach Authors. | ||
// | ||
// Use of this software is governed by the Business Source License | ||
// included in the file licenses/BSL.txt. | ||
// | ||
// As of the Change Date specified in that file, in accordance with | ||
// the Business Source License, use of this software will be governed | ||
// by the Apache License, Version 2.0, included in the file | ||
// licenses/APL.txt. | ||
|
||
package kvserver | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/kvflowcontrol/kvflowcontrolpb" | ||
"github.com/cockroachdb/cockroach/pkg/roachpb" | ||
"github.com/cockroachdb/cockroach/pkg/util/timeutil" | ||
"go.etcd.io/raft/v3" | ||
rafttracker "go.etcd.io/raft/v3/tracker" | ||
) | ||
|
||
// replicaForFlowControl abstracts the interface of an individual Replica, as | ||
// needed by replicaFlowControlIntegration. | ||
type replicaForFlowControl interface { | ||
annotateCtx(context.Context) context.Context | ||
getTenantID() roachpb.TenantID | ||
getReplicaID() roachpb.ReplicaID | ||
getRangeID() roachpb.RangeID | ||
getDescriptor() *roachpb.RangeDescriptor | ||
getAppliedLogPosition() kvflowcontrolpb.RaftLogPosition | ||
getPausedFollowers() map[roachpb.ReplicaID]struct{} | ||
isFollowerLive(context.Context, roachpb.ReplicaID) bool | ||
isRaftTransportConnectedTo(roachpb.StoreID) bool | ||
withReplicaProgress(f func(roachpb.ReplicaID, rafttracker.Progress)) | ||
|
||
assertLocked() // only affects test builds | ||
} | ||
|
||
// replicaFlowControl is a concrete implementation of the replicaForFlowControl | ||
// interface. | ||
type replicaFlowControl Replica | ||
|
||
var _ replicaForFlowControl = &replicaFlowControl{} | ||
|
||
func (rf *replicaFlowControl) assertLocked() { | ||
rf.mu.AssertHeld() | ||
} | ||
|
||
func (rf *replicaFlowControl) annotateCtx(ctx context.Context) context.Context { | ||
return rf.AnnotateCtx(ctx) | ||
} | ||
|
||
func (rf *replicaFlowControl) getTenantID() roachpb.TenantID { | ||
rf.assertLocked() | ||
return rf.mu.tenantID | ||
} | ||
|
||
func (rf *replicaFlowControl) getReplicaID() roachpb.ReplicaID { | ||
return rf.replicaID | ||
} | ||
|
||
func (rf *replicaFlowControl) getRangeID() roachpb.RangeID { | ||
return rf.RangeID | ||
} | ||
|
||
func (rf *replicaFlowControl) getDescriptor() *roachpb.RangeDescriptor { | ||
rf.assertLocked() | ||
r := (*Replica)(rf) | ||
return r.descRLocked() | ||
} | ||
|
||
func (rf *replicaFlowControl) getPausedFollowers() map[roachpb.ReplicaID]struct{} { | ||
rf.assertLocked() | ||
return rf.mu.pausedFollowers | ||
} | ||
|
||
func (rf *replicaFlowControl) isFollowerLive(ctx context.Context, replID roachpb.ReplicaID) bool { | ||
rf.mu.AssertHeld() | ||
return rf.mu.lastUpdateTimes.isFollowerActiveSince( | ||
ctx, | ||
replID, | ||
timeutil.Now(), | ||
rf.store.cfg.RangeLeaseDuration, | ||
) | ||
} | ||
|
||
func (rf *replicaFlowControl) isRaftTransportConnectedTo(storeID roachpb.StoreID) bool { | ||
rf.mu.AssertHeld() | ||
return rf.store.cfg.Transport.isConnectedTo(storeID) | ||
} | ||
|
||
func (rf *replicaFlowControl) getAppliedLogPosition() kvflowcontrolpb.RaftLogPosition { | ||
rf.mu.AssertHeld() | ||
status := rf.mu.internalRaftGroup.BasicStatus() | ||
return kvflowcontrolpb.RaftLogPosition{ | ||
Term: status.Term, | ||
Index: status.Applied, | ||
} | ||
} | ||
|
||
func (rf *replicaFlowControl) withReplicaProgress(f func(roachpb.ReplicaID, rafttracker.Progress)) { | ||
rf.mu.AssertHeld() | ||
rf.mu.internalRaftGroup.WithProgress(func(id uint64, _ raft.ProgressType, progress rafttracker.Progress) { | ||
f(roachpb.ReplicaID(id), progress) | ||
}) | ||
} |
Oops, something went wrong.