[ASTERIXDB-3530][OTH] Add throttle count to cloud rate limiter
- user model changes: no
- storage format changes: no
- interface changes: yes
Details:
- Refactor cloud request rate limiter classes.
- Add read/write throttle count to cloud rate limiter.
Ex-ref MB-62928
Change-Id: I174f90bfe5fd3a6b183dd9cf74d2a2ed89dae930
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/19094
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Murtadha Hubail <mhubail@apache.org>
Reviewed-by: Hussain Towaileb <hussainht@gmail.com>
diff --git a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/AbstractCloudRequestRateLimiter.java b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/AbstractCloudRequestRateLimiter.java
new file mode 100644
index 0000000..b1c1c94
--- /dev/null
+++ b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/AbstractCloudRequestRateLimiter.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.cloud.clients;
+
+import org.apache.asterix.cloud.clients.profiler.limiter.IRateLimiter;
+import org.apache.asterix.cloud.clients.profiler.limiter.IRequestRateLimiter;
+import org.apache.asterix.cloud.clients.profiler.limiter.NoOpRateLimiter;
+import org.apache.asterix.cloud.clients.profiler.limiter.TokenBasedRateLimiter;
+
+public abstract class AbstractCloudRequestRateLimiter implements IRequestRateLimiter {
+
+ protected final IRateLimiter writeLimiter;
+ protected final IRateLimiter readLimiter;
+
+ public AbstractCloudRequestRateLimiter(int writeMaxRequestsPerSeconds, int readMaxRequestsPerSeconds,
+ long tokenAcquireTimeout) {
+ this.writeLimiter = createLimiter(writeMaxRequestsPerSeconds, tokenAcquireTimeout);
+ this.readLimiter = createLimiter(readMaxRequestsPerSeconds, tokenAcquireTimeout);
+ }
+
+ @Override
+ public void writeRequest() {
+ writeLimiter.acquire();
+ }
+
+ @Override
+ public void readRequest() {
+ readLimiter.acquire();
+ }
+
+ @Override
+ public void listRequest() {
+ readLimiter.acquire();
+ }
+
+ @Override
+ public long getReadThrottleCount() {
+ return readLimiter.getThrottleCount();
+ }
+
+ @Override
+ public long getWriteThrottleCount() {
+ return writeLimiter.getThrottleCount();
+ }
+
+ private static IRateLimiter createLimiter(int maxRequestsPerSecond, long tokeAcquireTimeout) {
+ if (maxRequestsPerSecond > 0) {
+ return new TokenBasedRateLimiter(maxRequestsPerSecond, tokeAcquireTimeout);
+ }
+ return NoOpRateLimiter.INSTANCE;
+ }
+}
diff --git a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/aws/s3/S3RequestRateLimiter.java b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/aws/s3/S3RequestRateLimiter.java
index 37387a6..c2d730b 100644
--- a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/aws/s3/S3RequestRateLimiter.java
+++ b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/aws/s3/S3RequestRateLimiter.java
@@ -18,41 +18,12 @@
*/
package org.apache.asterix.cloud.clients.aws.s3;
-import org.apache.asterix.cloud.clients.profiler.limiter.IRateLimiter;
-import org.apache.asterix.cloud.clients.profiler.limiter.IRequestRateLimiter;
-import org.apache.asterix.cloud.clients.profiler.limiter.NoOpRateLimiter;
-import org.apache.asterix.cloud.clients.profiler.limiter.TokenBasedRateLimiter;
+import org.apache.asterix.cloud.clients.AbstractCloudRequestRateLimiter;
-public final class S3RequestRateLimiter implements IRequestRateLimiter {
- private final IRateLimiter writeLimiter;
- private final IRateLimiter readLimiter;
+public final class S3RequestRateLimiter extends AbstractCloudRequestRateLimiter {
public S3RequestRateLimiter(S3ClientConfig config) {
- long tokenAcquireTimeout = config.getTokenAcquireTimeout();
- this.writeLimiter = createLimiter(config.getWriteMaxRequestsPerSeconds(), tokenAcquireTimeout);
- this.readLimiter = createLimiter(config.getReadMaxRequestsPerSeconds(), tokenAcquireTimeout);
- }
-
- @Override
- public void writeRequest() {
- writeLimiter.acquire();
- }
-
- @Override
- public void readRequest() {
- readLimiter.acquire();
- }
-
- @Override
- public void listRequest() {
- // List requests in S3 are considered as PUT
- writeLimiter.acquire();
- }
-
- private static IRateLimiter createLimiter(int maxRequestsPerSecond, long tokeAcquireTimeout) {
- if (maxRequestsPerSecond > 0) {
- return new TokenBasedRateLimiter(maxRequestsPerSecond, tokeAcquireTimeout);
- }
- return NoOpRateLimiter.INSTANCE;
+ super(config.getWriteMaxRequestsPerSeconds(), config.getReadMaxRequestsPerSeconds(),
+ config.getTokenAcquireTimeout());
}
}
diff --git a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/azure/blobstorage/AzureRequestRateLimiter.java b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/azure/blobstorage/AzureRequestRateLimiter.java
index 6a76952..c97f3e6 100644
--- a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/azure/blobstorage/AzureRequestRateLimiter.java
+++ b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/azure/blobstorage/AzureRequestRateLimiter.java
@@ -18,40 +18,12 @@
*/
package org.apache.asterix.cloud.clients.azure.blobstorage;
-import org.apache.asterix.cloud.clients.profiler.limiter.IRateLimiter;
-import org.apache.asterix.cloud.clients.profiler.limiter.IRequestRateLimiter;
-import org.apache.asterix.cloud.clients.profiler.limiter.NoOpRateLimiter;
-import org.apache.asterix.cloud.clients.profiler.limiter.TokenBasedRateLimiter;
+import org.apache.asterix.cloud.clients.AbstractCloudRequestRateLimiter;
-public final class AzureRequestRateLimiter implements IRequestRateLimiter {
- private final IRateLimiter writeLimiter;
- private final IRateLimiter readLimiter;
+public final class AzureRequestRateLimiter extends AbstractCloudRequestRateLimiter {
public AzureRequestRateLimiter(AzBlobStorageClientConfig config) {
- long tokenAcquireTimeout = config.getTokenAcquireTimeout();
- this.writeLimiter = createLimiter(config.getWriteMaxRequestsPerSeconds(), tokenAcquireTimeout);
- this.readLimiter = createLimiter(config.getReadMaxRequestsPerSeconds(), tokenAcquireTimeout);
- }
-
- @Override
- public void writeRequest() {
- writeLimiter.acquire();
- }
-
- @Override
- public void readRequest() {
- readLimiter.acquire();
- }
-
- @Override
- public void listRequest() {
- readLimiter.acquire();
- }
-
- private static IRateLimiter createLimiter(int maxRequestsPerSecond, long tokeAcquireTimeout) {
- if (maxRequestsPerSecond > 0) {
- return new TokenBasedRateLimiter(maxRequestsPerSecond, tokeAcquireTimeout);
- }
- return NoOpRateLimiter.INSTANCE;
+ super(config.getWriteMaxRequestsPerSeconds(), config.getReadMaxRequestsPerSeconds(),
+ config.getTokenAcquireTimeout());
}
}
diff --git a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/google/gcs/GCSRequestRateLimiter.java b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/google/gcs/GCSRequestRateLimiter.java
index 71f6b8c..a68c3f9 100644
--- a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/google/gcs/GCSRequestRateLimiter.java
+++ b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/google/gcs/GCSRequestRateLimiter.java
@@ -18,40 +18,12 @@
*/
package org.apache.asterix.cloud.clients.google.gcs;
-import org.apache.asterix.cloud.clients.profiler.limiter.IRateLimiter;
-import org.apache.asterix.cloud.clients.profiler.limiter.IRequestRateLimiter;
-import org.apache.asterix.cloud.clients.profiler.limiter.NoOpRateLimiter;
-import org.apache.asterix.cloud.clients.profiler.limiter.TokenBasedRateLimiter;
+import org.apache.asterix.cloud.clients.AbstractCloudRequestRateLimiter;
-public class GCSRequestRateLimiter implements IRequestRateLimiter {
- private final IRateLimiter writeLimiter;
- private final IRateLimiter readLimiter;
+public class GCSRequestRateLimiter extends AbstractCloudRequestRateLimiter {
public GCSRequestRateLimiter(GCSClientConfig config) {
- long tokenAcquireTimeout = config.getTokenAcquireTimeout();
- this.writeLimiter = createLimiter(config.getWriteMaxRequestsPerSeconds(), tokenAcquireTimeout);
- this.readLimiter = createLimiter(config.getReadMaxRequestsPerSeconds(), tokenAcquireTimeout);
- }
-
- @Override
- public void writeRequest() {
- writeLimiter.acquire();
- }
-
- @Override
- public void readRequest() {
- readLimiter.acquire();
- }
-
- @Override
- public void listRequest() {
- readLimiter.acquire();
- }
-
- private static IRateLimiter createLimiter(int maxRequestsPerSecond, long tokeAcquireTimeout) {
- if (maxRequestsPerSecond > 0) {
- return new TokenBasedRateLimiter(maxRequestsPerSecond, tokeAcquireTimeout);
- }
- return NoOpRateLimiter.INSTANCE;
+ super(config.getWriteMaxRequestsPerSeconds(), config.getReadMaxRequestsPerSeconds(),
+ config.getTokenAcquireTimeout());
}
}
diff --git a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/CountRequestProfilerLimiter.java b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/CountRequestProfilerLimiter.java
index 16ffb7a..95383f6 100644
--- a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/CountRequestProfilerLimiter.java
+++ b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/CountRequestProfilerLimiter.java
@@ -140,6 +140,16 @@
return multipartDownloadCounter.get();
}
+ @Override
+ public long getReadThrottleCount() {
+ return limiter.getReadThrottleCount();
+ }
+
+ @Override
+ public long getWriteThrottleCount() {
+ return limiter.getWriteThrottleCount();
+ }
+
private void log() {
if (LOGGER.isEnabled(LOG_LEVEL)) {
long currentTime = System.nanoTime();
diff --git a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/IRequestProfilerLimiter.java b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/IRequestProfilerLimiter.java
index b86cd48..fc0cbef 100644
--- a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/IRequestProfilerLimiter.java
+++ b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/IRequestProfilerLimiter.java
@@ -47,4 +47,7 @@
long objectMultipartDownloadCount();
+ long getReadThrottleCount();
+
+ long getWriteThrottleCount();
}
diff --git a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/NoOpRequestProfilerLimiter.java b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/NoOpRequestProfilerLimiter.java
index ab658f5..832457b 100644
--- a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/NoOpRequestProfilerLimiter.java
+++ b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/NoOpRequestProfilerLimiter.java
@@ -93,4 +93,14 @@
public long objectMultipartDownloadCount() {
return 0;
}
+
+ @Override
+ public long getReadThrottleCount() {
+ return 0;
+ }
+
+ @Override
+ public long getWriteThrottleCount() {
+ return 0;
+ }
}
diff --git a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/RequestLimiterNoOpProfiler.java b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/RequestLimiterNoOpProfiler.java
index cce2f8e..9d5118a 100644
--- a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/RequestLimiterNoOpProfiler.java
+++ b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/RequestLimiterNoOpProfiler.java
@@ -96,4 +96,14 @@
public long objectMultipartDownloadCount() {
return 0;
}
+
+ @Override
+ public long getReadThrottleCount() {
+ return limiter.getReadThrottleCount();
+ }
+
+ @Override
+ public long getWriteThrottleCount() {
+ return limiter.getWriteThrottleCount();
+ }
}
diff --git a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/IRateLimiter.java b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/IRateLimiter.java
index 741735b..883990d 100644
--- a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/IRateLimiter.java
+++ b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/IRateLimiter.java
@@ -26,4 +26,11 @@
* Acquire permit or wait if rate limit exceeded
*/
void acquire();
+
+ /**
+ * Get the number of throttled requests
+ *
+ * @return the number of throttled requests
+ */
+ long getThrottleCount();
}
diff --git a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/IRequestRateLimiter.java b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/IRequestRateLimiter.java
index 98b2eab..bc5bdbd 100644
--- a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/IRequestRateLimiter.java
+++ b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/IRequestRateLimiter.java
@@ -37,4 +37,18 @@
* Perform a list request
*/
void listRequest();
+
+ /**
+ * Get the number of throttled read requests
+ *
+ * @return the number of throttled read requests
+ */
+ long getReadThrottleCount();
+
+ /**
+ * Get the number of throttled write requests
+ *
+ * @return the number of throttled write requests
+ */
+ long getWriteThrottleCount();
}
diff --git a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/NoOpRateLimiter.java b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/NoOpRateLimiter.java
index 4dd8c88..356538e 100644
--- a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/NoOpRateLimiter.java
+++ b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/NoOpRateLimiter.java
@@ -28,4 +28,9 @@
public void acquire() {
// NoOp
}
+
+ @Override
+ public long getThrottleCount() {
+ return 0;
+ }
}
diff --git a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/NoOpRequestLimiter.java b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/NoOpRequestLimiter.java
index ea89a2e..182d925 100644
--- a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/NoOpRequestLimiter.java
+++ b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/NoOpRequestLimiter.java
@@ -38,4 +38,14 @@
public void listRequest() {
// NoOp
}
+
+ @Override
+ public long getReadThrottleCount() {
+ return 0;
+ }
+
+ @Override
+ public long getWriteThrottleCount() {
+ return 0;
+ }
}
diff --git a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/TokenBasedRateLimiter.java b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/TokenBasedRateLimiter.java
index a0273fb..564e1c2 100644
--- a/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/TokenBasedRateLimiter.java
+++ b/asterixdb/asterix-cloud/src/main/java/org/apache/asterix/cloud/clients/profiler/limiter/TokenBasedRateLimiter.java
@@ -28,6 +28,7 @@
public final class TokenBasedRateLimiter implements IRateLimiter {
private static final Logger LOGGER = LogManager.getLogger();
private static final long SECOND_NANO = TimeUnit.SECONDS.toNanos(1);
+ private final AtomicLong throttleCount = new AtomicLong();
private final long acquireTimeoutNano;
private final int maxTokensPerSecond;
private final Semaphore semaphore;
@@ -54,6 +55,7 @@
if (semaphore.tryAcquire(acquireTimeoutNano, TimeUnit.NANOSECONDS)) {
return;
}
+ throttleCount.incrementAndGet();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LOGGER.debug("Interrupted while waiting for acquiring a request token", e);
@@ -62,6 +64,11 @@
}
}
+ @Override
+ public long getThrottleCount() {
+ return throttleCount.get();
+ }
+
private void refillTokens() {
long refillTime = lastRefillTime.get();
long now = System.nanoTime();