Skip to content

Commit 3d404ca

Browse files
committed
Rate Limting
Added Rate Limiting Sample
1 parent 438a360 commit 3d404ca

File tree

17 files changed

+704
-35
lines changed

17 files changed

+704
-35
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1-
1+
.idea
2+
*.iml
23
.DS_Store
4+
/target

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,45 @@ basic.request.default-idempotence = true
2020
}
2121
```
2222

23+
## Throttling - RateLimiting
24+
Retries maintain level of availability when receiving short burst of traffic, acute failure, or loss of connection, but sustained retries can further destabilize systems resulting in cascading failure. If you are using retries to limit traffic then you may want to consider a rate limiter. As reties continue to occur at a steady rate they increasingly add to the overall traffic sent to the database. When facing this scenario you should introduce rate-limiting. Rate limiters provide what is known as back pressure. You can achieve this by leveraging the Java Driver's Throttler Extension point. There are a few rate-limiters provided native with the driver, but in this repository we will provide some sample limiters that are designed for Amazon Keyspaces serverless capacity and service quotas.
25+
26+
### AmazonKeyspacesFixedRateThrottler
27+
This is a request throttler that limits the rate of requests per second. It can be used to match the current table provisioned rate if you have predictable or average capacity per request.
28+
The limit is configurable through the client driver configuration.
29+
The rate of request is controlled by Guava SmoothBursty Ratelimiter that allows two minutes of capacity to aggregate if not used.
30+
The second limiter is dynamically configured based on the number of connections defined in the pool setting that limits overall throughput during burst behavior.
31+
The limiter will control the number of cql request per second but expects the table to have proper capacity defined to achieve utilization.
32+
This is a blocking implementation, but has a configurable timeout.
33+
34+
The most well-known use-case for this type of rate limiter is bulk loading data at consistent rates or batch processing. In the image below we are able to utilize 100 percent of the table's capacity without error by fixing the request rate to the table write capacity. The workload gradually stepped up throughput level all the way up to 3x the request rate of the table's provisioned capacity. Additionally, since the rate limiter allows for bursting, we are able to use burst capacity of the table that can accrue when provisioned capacity is not fully utilized. The fixed are limiter can also be used with On-Demand Capacity Tables to fit within current account specific table quotas.
35+
![Rate Limiting](/static/images/RateLimiting.png)
36+
37+
To activate this throttler, modify the {@code advanced.throttler} section in the driver configuration, for example:
38+
39+
```
40+
datastax-java-driver {
41+
advanced.throttler = {
42+
class = com.aws.ssa.keyspaces.throttler.AmazonKeyspacesFixedRateThrottler
43+
max-requests-per-second = 1000
44+
endpoint-type = VPC
45+
register-timeout = 1 seconds
46+
}
47+
}
48+
```
49+
50+
51+
52+
* `max-requests-per-second` : controls the request rate. Blocks until available permits or timeout it reached
53+
* `endpoint-type` : if you are connected to the VPC endpoint or the public endpoint. Used to determine throughput based on the number of connections specified in:`advanced.connection.pool.local.size`
54+
* `register-timeout` timeout waiting for permits. Should be less than or equal to `basic.request.timeout'
55+
56+
57+
# Build this project
58+
To build and use this library execute the following mvn command and place on the classpath of your application.
59+
```
60+
mvn clean package
61+
```
2362
# Security
2463

2564
See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information.

pom.xml

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,22 @@
44
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
55
<modelVersion>4.0.0</modelVersion>
66

7-
<groupId>org.example</groupId>
7+
<groupId>com.aws.ssa.keyspaces</groupId>
88
<artifactId>amazon-keyspaces-helpers</artifactId>
99
<version>1.0-SNAPSHOT</version>
1010

1111
<properties>
1212
<maven.compiler.source>1.8</maven.compiler.source>
1313
<maven.compiler.target>1.8</maven.compiler.target>
14-
1514
<aws.java.sdk.version>2.13.7</aws.java.sdk.version>
16-
1715
</properties>
1816

1917

2018
<dependencies>
21-
2219
<dependency>
2320
<groupId>com.datastax.oss</groupId>
2421
<artifactId>java-driver-core</artifactId>
25-
<version>4.10.0</version>
22+
<version>4.2.0</version>
2623
<scope>provided</scope>
2724
</dependency>
2825
<dependency>
@@ -43,16 +40,9 @@
4340
<version>1.2.3</version>
4441
<scope>test</scope>
4542
</dependency>
46-
<dependency>
47-
<groupId>io.dropwizard.metrics</groupId>
48-
<artifactId>metrics-core</artifactId>
49-
<version>4.1.0</version>
50-
<scope>test</scope>
51-
</dependency>
5243
</dependencies>
5344

5445
<build>
55-
5646
<plugins>
5747
<plugin>
5848
<artifactId>maven-assembly-plugin</artifactId>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.aws.ssa.keyspaces.core;
2+
3+
public enum EndpointType {
4+
VPC,
5+
PUBLIC;
6+
}

src/main/java/com/aws/ssa/keyspaces/retry/AmazonKeyspacesRetryPolicy.java

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,10 @@ public RetryDecision onReadTimeout(
105105
boolean dataPresent,
106106
int retryCount) {
107107

108-
109108
RetryDecision decision = determineRetryDecision(retryCount);
110109

111-
if (LOG.isTraceEnabled() && (decision == RetryDecision.RETRY_SAME || decision == RetryDecision.RETHROW)) {
112-
LOG.trace(RETRYING_ON_READ_TIMEOUT, logPrefix, cl, blockFor, received, false, retryCount);
113-
}
114-
110+
LOG.trace(RETRYING_ON_READ_TIMEOUT, logPrefix, cl, blockFor, received, false, retryCount);
111+
115112
return decision;
116113

117114
}
@@ -133,12 +130,10 @@ public RetryDecision onWriteTimeout(
133130
int received,
134131
int retryCount) {
135132

136-
137133
RetryDecision decision = determineRetryDecision(retryCount);
138134

139-
if (LOG.isTraceEnabled() && (decision == RetryDecision.RETRY_SAME || decision == RetryDecision.RETHROW)) {
140-
LOG.trace(RETRYING_ON_WRITE_TIMEOUT, logPrefix, cl, blockFor, received, false, retryCount);
141-
}
135+
LOG.trace(RETRYING_ON_WRITE_TIMEOUT, logPrefix, cl, blockFor, received, false, retryCount);
136+
142137

143138
return decision;
144139
}
@@ -160,9 +155,8 @@ public RetryDecision onUnavailable(
160155

161156
RetryDecision decision = determineRetryDecision(retryCount);
162157

163-
if (LOG.isTraceEnabled() && (decision == RetryDecision.RETRY_SAME || decision == RetryDecision.RETHROW)) {
164-
LOG.trace(RETRYING_ON_UNAVAILABLE, logPrefix, cl, required, alive, retryCount);
165-
}
158+
LOG.trace(RETRYING_ON_UNAVAILABLE, logPrefix, cl, required, alive, retryCount);
159+
166160

167161
return decision;
168162
}
@@ -175,11 +169,11 @@ public RetryDecision onUnavailable(
175169
@Override
176170
public RetryDecision onRequestAborted(
177171
@NonNull Request request, @NonNull Throwable error, int retryCount) {
172+
178173
RetryDecision decision = determineRetryDecision(retryCount);
179174

180-
if (LOG.isTraceEnabled() && (decision == RetryDecision.RETRY_SAME || decision == RetryDecision.RETHROW)) {
181-
LOG.trace(RETRYING_ON_ABORTED, logPrefix, retryCount, error);
182-
}
175+
LOG.trace(RETRYING_ON_ABORTED, logPrefix, retryCount, error);
176+
183177

184178
return decision;
185179
}
@@ -193,12 +187,9 @@ public RetryDecision onRequestAborted(
193187
public RetryDecision onErrorResponse(
194188
@NonNull Request request, @NonNull CoordinatorException error, int retryCount) {
195189

196-
197190
RetryDecision decision = determineRetryDecision(retryCount);
198191

199-
if (LOG.isTraceEnabled() && (decision == RetryDecision.RETRY_SAME || decision == RetryDecision.RETHROW)) {
200-
LOG.trace(RETRYING_ON_ERROR, logPrefix, retryCount, error);
201-
}
192+
LOG.trace(RETRYING_ON_ERROR, logPrefix, retryCount, error);
202193

203194
return decision;
204195
}

0 commit comments

Comments
 (0)