From d3c15f2866504abc0c9a8e8bbc0d393f0b3bd2ce Mon Sep 17 00:00:00 2001 From: elandau Date: Fri, 22 Mar 2019 06:38:54 -0700 Subject: [PATCH 1/2] AIMD Bounds --- .../concurrency/limits/limit/AIMDLimit.java | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/concurrency-limits-core/src/main/java/com/netflix/concurrency/limits/limit/AIMDLimit.java b/concurrency-limits-core/src/main/java/com/netflix/concurrency/limits/limit/AIMDLimit.java index 1addef4c..940d13d6 100644 --- a/concurrency-limits-core/src/main/java/com/netflix/concurrency/limits/limit/AIMDLimit.java +++ b/concurrency-limits-core/src/main/java/com/netflix/concurrency/limits/limit/AIMDLimit.java @@ -28,7 +28,9 @@ public final class AIMDLimit extends AbstractLimit { private static final long DEFAULT_TIMEOUT = TimeUnit.SECONDS.toNanos(5); public static class Builder { - private int initialLimit = 10; + private int minLimit = 20; + private int initialLimit = 20; + private int maxLimit = 200; private double backoffRatio = 0.9; private long timeout = DEFAULT_TIMEOUT; @@ -37,6 +39,16 @@ public Builder initialLimit(int initialLimit) { return this; } + public Builder minLimit(int minLimit) { + this.minLimit = minLimit; + return this; + } + + public Builder maxLimit(int maxLimit) { + this.maxLimit = maxLimit; + return this; + } + public Builder backoffRatio(double backoffRatio) { Preconditions.checkArgument(backoffRatio < 1.0 && backoffRatio >= 0.5, "Backoff ratio must be in the range [0.5, 1.0)"); this.backoffRatio = backoffRatio; @@ -66,24 +78,32 @@ public static Builder newBuilder() { private final double backoffRatio; private final long timeout; + private final int minLimit; + private final int maxLimit; private AIMDLimit(Builder builder) { super(builder.initialLimit); this.backoffRatio = builder.backoffRatio; this.timeout = builder.timeout; + this.maxLimit = builder.maxLimit; + this.minLimit = builder.minLimit; } @Override protected int _update(long startTime, long rtt, int inflight, boolean didDrop) { - final int currentLimit = getLimit(); + int currentLimit = getLimit(); if (didDrop || rtt > timeout) { - return Math.max(1, Math.min(currentLimit - 1, (int) (currentLimit * backoffRatio))); + currentLimit = (int) (currentLimit * backoffRatio); } else if (inflight * 2 >= currentLimit) { - return currentLimit + 1; - } else { - return currentLimit; + currentLimit = currentLimit + 1; + } + + if (currentLimit >= maxLimit) { + currentLimit = currentLimit / 2; } + + return Math.min(maxLimit, Math.max(minLimit, currentLimit)); } @Override From afbbed455123f9d8318e9a7001e085da27d68ab1 Mon Sep 17 00:00:00 2001 From: elandau Date: Fri, 22 Mar 2019 17:31:33 -0700 Subject: [PATCH 2/2] Fix unit test --- .../netflix/concurrency/limits/limit/AIMDLimitTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/concurrency-limits-core/src/test/java/com/netflix/concurrency/limits/limit/AIMDLimitTest.java b/concurrency-limits-core/src/test/java/com/netflix/concurrency/limits/limit/AIMDLimitTest.java index 4e08e39a..d4379c57 100644 --- a/concurrency-limits-core/src/test/java/com/netflix/concurrency/limits/limit/AIMDLimitTest.java +++ b/concurrency-limits-core/src/test/java/com/netflix/concurrency/limits/limit/AIMDLimitTest.java @@ -14,15 +14,15 @@ public void testDefault() { @Test public void increaseOnSuccess() { - AIMDLimit limiter = AIMDLimit.newBuilder().initialLimit(10).build(); + AIMDLimit limiter = AIMDLimit.newBuilder().initialLimit(20).build(); limiter.onSample(0, TimeUnit.MILLISECONDS.toNanos(1), 10, false); - Assert.assertEquals(11, limiter.getLimit()); + Assert.assertEquals(21, limiter.getLimit()); } @Test public void decreaseOnDrops() { - AIMDLimit limiter = AIMDLimit.newBuilder().initialLimit(10).build(); + AIMDLimit limiter = AIMDLimit.newBuilder().initialLimit(30).build(); limiter.onSample(0, 0, 0, true); - Assert.assertEquals(9, limiter.getLimit()); + Assert.assertEquals(27, limiter.getLimit()); } }