Skip to content

Commit 423d76c

Browse files
committed
implement replay side throttling
1 parent f107f23 commit 423d76c

6 files changed

Lines changed: 84 additions & 1 deletion

File tree

libs/cluster/Server/Replication/ReplicaOps/AOFReplay/ReplicaReplayDriver.cs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ internal sealed class ReplicaReplayDriver : IBulkLogEntryConsumer, IDisposable
3434
readonly TsavoriteLog physicalSublog;
3535
readonly bool useChannels = false;
3636

37+
int throttleCounter;
38+
3739
[MethodImpl(MethodImplOptions.AggressiveInlining)]
3840
public bool ResumeReplay() => activeWorkerMonitor.TryEnter();
3941

@@ -270,7 +272,52 @@ private unsafe void ConsumeDirect(byte* record, int recordLength, long currentAd
270272
}
271273
}
272274

273-
public void Throttle() { }
275+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
276+
public void Throttle()
277+
{
278+
if (serverOptions.AofPhysicalSublogCount <= 1)
279+
return;
280+
281+
var w = serverOptions.AofReplayMaxDrift;
282+
if (w <= 0)
283+
return;
284+
285+
if (++throttleCounter < w)
286+
return;
287+
throttleCounter = 0;
288+
ThrottleSlow(w);
289+
290+
void ThrottleSlow(long w)
291+
{
292+
var rcm = appendOnlyFile.readConsistencyManager;
293+
if (rcm == null)
294+
return;
295+
296+
var myMax = rcm.GetPhysicalSublogMax(physicalSublogIdx);
297+
298+
// If we're too far ahead, wait until all peers reach our current max
299+
if (!AllPeersReached(rcm, Math.Max(myMax - w, w)))
300+
{
301+
do
302+
{
303+
cts.Token.ThrowIfCancellationRequested();
304+
Thread.Yield();
305+
} while (!AllPeersReached(rcm, myMax));
306+
}
307+
308+
bool AllPeersReached(ReadConsistencyManager rcm, long target)
309+
{
310+
for (var i = 0; i < serverOptions.AofPhysicalSublogCount; i++)
311+
{
312+
if (i == physicalSublogIdx)
313+
continue;
314+
if (rcm.GetPhysicalSublogMax(i) < target)
315+
return false;
316+
}
317+
return true;
318+
}
319+
}
320+
}
274321
#endregion
275322

276323
[MethodImpl(MethodImplOptions.AggressiveInlining)]

libs/host/Configuration/Options.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,9 @@ internal sealed class Options : ICloneable
212212
[Option("aof-replay-task-count", Required = false, HelpText = "Number of replay tasks per physical sublog at the replica.")]
213213
public int AofReplayTaskCount { get; set; }
214214

215+
[Option("aof-replay-max-drift", Required = false, HelpText = "Maximum allowed drift in key sequence numbers between physical sublog replay drivers. When a driver is ahead of the slowest peer by more than this value, it yields. Only effective when aof-physical-sublog-count > 1. -1 = disabled.")]
216+
public long AofReplayMaxDrift { get; set; }
217+
215218
[IntRangeValidation(0, int.MaxValue)]
216219
[Option("aof-tail-witness-freq", Required = false, HelpText = "Polling frequency of the background task responsible for moving time ahead for all physical sublogs (Used only with physical sublog value >1).")]
217220
public int AofTailWitnessFreqMs { get; set; }
@@ -859,6 +862,7 @@ endpoint is IPEndPoint listenEp && clusterAnnounceEndpoint[0] is IPEndPoint anno
859862
AofSegmentSize = AofSegmentSize,
860863
AofPhysicalSublogCount = AofPhysicalSublogCount,
861864
AofReplayTaskCount = AofReplayTaskCount,
865+
AofReplayMaxDrift = AofReplayMaxDrift,
862866
AofTailWitnessFreqMs = AofTailWitnessFreqMs,
863867
CommitFrequencyMs = CommitFrequencyMs,
864868
WaitForCommit = WaitForCommit.GetValueOrDefault(),

libs/host/defaults.conf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@
145145
/* Number of replay tasks per physical sublog at the replica. */
146146
"AofReplayTaskCount": 1,
147147

148+
/* Maximum allowed drift in key sequence numbers between physical sublog replay drivers. -1 = disabled. */
149+
"AofReplayMaxDrift": -1,
150+
148151
/* Polling frequency of the background task responsible for moving time ahead for all physical sublogs (Used only with physical sublog value >1). */
149152
"AofTailWitnessFreqMs": 10,
150153

libs/server/AOF/ReadConsistency/ReadConsistencyManager.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,23 @@ public AofAddress GetPhysicalSublogMaxReplayedSequenceNumber()
5454
return maxKeySeqNumVector;
5555
}
5656

57+
/// <summary>
58+
/// Gets the maximum replayed sequence number for a single physical sublog
59+
/// by reading the max across all its virtual sublogs.
60+
/// </summary>
61+
/// <param name="physicalSublogIdx">Physical sublog index.</param>
62+
/// <returns>The maximum sequence number observed across all virtual sublogs for this physical sublog.</returns>
63+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
64+
public long GetPhysicalSublogMax(int physicalSublogIdx)
65+
{
66+
var replayTaskCount = serverOptions.AofReplayTaskCount;
67+
var startIdx = appendOnlyFile.GetVirtualSublogIdx(physicalSublogIdx, 0);
68+
long max = 0;
69+
for (var rt = 0; rt < replayTaskCount; rt++)
70+
max = Math.Max(max, Volatile.Read(ref vsrs[startIdx + rt].MaxRef));
71+
return max;
72+
}
73+
5774
/// <summary>
5875
/// Get frontier sequence number for provided hash
5976
/// NOTE: Frontier sequence number is maximum sequence number between key specific sequence number and maximum observed sublog sequence number

libs/server/AOF/ReadConsistency/VirtualSublogReplayState.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ sealed class SublogReplayStateMax
4444

4545
public readonly long Max => sketchMax.Value;
4646

47+
/// <summary>
48+
/// Reference to the max value for Volatile.Read access from external callers.
49+
/// </summary>
50+
public ref long MaxRef => ref sketchMax.Value;
51+
4752
public VirtualSublogReplayState()
4853
{
4954
var size = SketchSlotSize;

libs/server/Servers/GarnetServerOptions.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,13 @@ public class GarnetServerOptions : ServerOptions
8787
/// </summary>
8888
public int AofReplayTaskCount = 1;
8989

90+
/// <summary>
91+
/// Maximum allowed drift (in key sequence numbers) between the fastest and slowest physical sublog replay drivers.
92+
/// When a driver is ahead of the slowest peer by more than this value, it yields until the gap closes.
93+
/// Only effective when AofPhysicalSublogCount > 1. -1 = disabled (no throttling).
94+
/// </summary>
95+
public long AofReplayMaxDrift = -1;
96+
9097
/// <summary>
9198
/// Polling frequency of the background task responsible for moving time ahead for all physical sublogs (Used only with physical sublog value >1).
9299
/// </summary>

0 commit comments

Comments
 (0)