Skip to content

Commit b7b6dec

Browse files
committed
Refactor SmoothWarmupLimiter and TokenBucketLimiter to improve wait time calculations and enhance logic for permit handling
1 parent 4410c00 commit b7b6dec

File tree

2 files changed

+36
-7
lines changed

2 files changed

+36
-7
lines changed

joylive-core/joylive-governance-api/src/main/java/com/jd/live/agent/governance/invoke/ratelimit/tokenbucket/SmoothWarmupLimiter.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import com.jd.live.agent.governance.policy.service.limit.RateLimitPolicy;
1717
import com.jd.live.agent.governance.policy.service.limit.SlidingWindow;
1818

19+
import static java.lang.Math.min;
1920

2021
/**
2122
* SmoothWarmupLimiter
@@ -82,9 +83,27 @@ protected double getMaxStoredPermits() {
8283
return thresholdPermits + 2.0 * warmupMicros / (permitIntervalMicros + coldIntervalMicros);
8384
}
8485

86+
@Override
87+
protected long waitForStorePermits(double storedPermits, double targetPermits) {
88+
double availablePermitsAboveThreshold = storedPermits - thresholdPermits;
89+
long micros = 0;
90+
// measuring the integral on the right part of the function (the climbing line)
91+
if (availablePermitsAboveThreshold > 0.0) {
92+
double permitsAboveThresholdToTake = min(availablePermitsAboveThreshold, targetPermits);
93+
double length =
94+
permitsToTime(availablePermitsAboveThreshold)
95+
+ permitsToTime(availablePermitsAboveThreshold - permitsAboveThresholdToTake);
96+
micros = (long) (permitsAboveThresholdToTake * length / 2.0);
97+
targetPermits -= permitsAboveThresholdToTake;
98+
}
99+
// measuring the integral on the left part of the function (the horizontal line)
100+
micros += (long) (permitIntervalMicros * targetPermits);
101+
return micros;
102+
}
103+
85104
@Override
86105
protected double coolDownIntervalMicros() {
87-
return storedPermits > thresholdPermits ? coldIntervalMicros : permitIntervalMicros;
106+
return warmupMicros / maxStoredPermits;
88107
}
89108

90109
private double permitsToTime(double permits) {

joylive-core/joylive-governance-api/src/main/java/com/jd/live/agent/governance/invoke/ratelimit/tokenbucket/TokenBucketLimiter.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,16 +154,26 @@ protected boolean isOver() {
154154
protected long waitForRequiredPermits(long permits, long startTimeMicros, long timeoutMicros) {
155155
long nowMicros = stopwatch.readMicros();
156156
refresh(nowMicros);
157-
double available = min(permits, storedPermits);
158-
double lack = permits - available;
159-
long waitTimeMicros = waitForStorePermits(storedPermits, available) + (long) (lack * permitIntervalMicros);
160-
long momentAvailable = saturatedAdd(this.nextPermitMicros, waitTimeMicros);
161157

162-
long microsToSleep = max(0L, momentAvailable - nowMicros);
158+
// 1. First, calculate the time needed to wait for the current request itself.
159+
// If the current time has already exceeded nextPermitMicros, there is no need to wait (wait = 0).
160+
// If the current time has not yet reached nextPermitMicros (which is a hole left by the previous request), then a wait is required.
161+
long microsToSleep = max(0L, this.nextPermitMicros - nowMicros);
162+
163+
// 2. Check if there is a timeout
164+
// Only when the "debt of the ancestors" is too heavy, and the time I need to wait exceeds my Timeout, do I give up.
163165
if (microsToSleep > timeoutMicros) {
164166
return TIMEOUT;
165167
}
166-
this.nextPermitMicros = momentAvailable;
168+
169+
// 3. Calculate the additional time cost of consuming the token for this request (this is the pit I'm leaving for posterity)
170+
double available = min(permits, storedPermits);
171+
double lack = permits - available;
172+
long waitTimeMicros = waitForStorePermits(storedPermits, available) + (long) (lack * permitIntervalMicros);
173+
174+
// 4.Time to update next token available = current next time + cost incurred this time
175+
this.nextPermitMicros = saturatedAdd(this.nextPermitMicros, waitTimeMicros);
176+
167177
storedPermits -= available;
168178
return microsToSleep;
169179
}

0 commit comments

Comments
 (0)