Skip to content

Commit e188995

Browse files
authored
Apache5x SDkBenhmark Tests (#6206)
* Fix architecture test failures for apache5.x * Checkstyle issues * Update to use PoolingHttpClientConnectionManager class reference that is implementation of HttpClientConnectionManager * Fix stream reset failure in RepeatableInputStreamRequestEntity by storing content reference to avoid multiple ContentStreamProvider.newStream() calls that cause IOException when retrying requests with non-resettable streams * writeTo_ConcurrentWrites_HandlesCorrectly no longer needed since even Apache 4.x doesnot suports this * Fix connectionPoolingWorks by setting skipping setConnectionTimeToLive is value is set to 0 since 0 is treated as Infinite timeToLive in Sdk and Apache 4.x but treated as immediate closeConnection in apache 5.x * disableAutomaticRetries in Apache 5.x since SDK handles retries , also define Apache5 dependencies in .brazil.json * Added Test case for Async , handled review ocmments * Donot do buffer the response using BufferedHttpEntity since it might cause memory issue, this behaviour is same as Apache4.x * Fix compilation issues * Fix checkstyle issues * Remove test which are specific to apache http * Add benchmark for Apache5 and add Streaming Api test cases
1 parent a959581 commit e188995

File tree

6 files changed

+270
-6
lines changed

6 files changed

+270
-6
lines changed

test/s3-benchmarks/pom.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,17 @@
102102
<artifactId>netty-nio-client</artifactId>
103103
<version>${awsjavasdk.version}</version>
104104
</dependency>
105+
<dependency>
106+
<artifactId>apache-client</artifactId>
107+
<groupId>software.amazon.awssdk</groupId>
108+
<version>${awsjavasdk.version}</version>
109+
</dependency>
110+
<dependency>
111+
<artifactId>apache5-client</artifactId>
112+
<groupId>software.amazon.awssdk</groupId>
113+
<version>${awsjavasdk.version}</version>
114+
</dependency>
115+
105116
<dependency>
106117
<groupId>software.amazon.awssdk</groupId>
107118
<artifactId>aws-crt-client</artifactId>

test/sdk-benchmarks/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,11 @@
158158
<artifactId>apache-client</artifactId>
159159
<version>${awsjavasdk.version}</version>
160160
</dependency>
161+
<dependency>
162+
<groupId>software.amazon.awssdk</groupId>
163+
<artifactId>apache5-client</artifactId>
164+
<version>${awsjavasdk.version}</version>
165+
</dependency>
161166
<dependency>
162167
<groupId>software.amazon.awssdk</groupId>
163168
<artifactId>protocol-tests</artifactId>

test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/httpclient/SdkHttpClientBenchmark.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,39 @@ public interface SdkHttpClientBenchmark {
4040
*/
4141
default void concurrentApiCall(Blackhole blackhole) {
4242
}
43+
44+
45+
/**
46+
* Benchmark for PUT operations with streaming
47+
*
48+
* @param blackhole the blackhole
49+
*/
50+
default void streamingPutOperation(Blackhole blackhole) {
51+
}
52+
53+
/**
54+
* Benchmark for concurrent PUT operations
55+
*
56+
* @param blackhole the blackhole
57+
*/
58+
default void concurrentStreamingPutOperation(Blackhole blackhole) {
59+
}
60+
61+
/**
62+
* Benchmark for GET operations with streaming response
63+
*
64+
* @param blackhole the blackhole
65+
*/
66+
default void streamingOutputOperation(Blackhole blackhole) {
67+
}
68+
69+
/**
70+
* Benchmark for concurrent GET operations with streaming response
71+
*
72+
* @param blackhole the blackhole
73+
*/
74+
default void concurrentStreamingOutputOperation(Blackhole blackhole) {
75+
}
76+
77+
4378
}

test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/apicall/httpclient/sync/ApacheHttpClientBenchmark.java

Lines changed: 106 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,26 +33,35 @@
3333
import org.openjdk.jmh.annotations.Measurement;
3434
import org.openjdk.jmh.annotations.Mode;
3535
import org.openjdk.jmh.annotations.OperationsPerInvocation;
36+
import org.openjdk.jmh.annotations.Param;
3637
import org.openjdk.jmh.annotations.Scope;
3738
import org.openjdk.jmh.annotations.Setup;
3839
import org.openjdk.jmh.annotations.State;
3940
import org.openjdk.jmh.annotations.TearDown;
4041
import org.openjdk.jmh.annotations.Warmup;
4142
import org.openjdk.jmh.infra.Blackhole;
43+
import org.openjdk.jmh.profile.GCProfiler;
4244
import org.openjdk.jmh.profile.StackProfiler;
4345
import org.openjdk.jmh.results.RunResult;
4446
import org.openjdk.jmh.runner.Runner;
4547
import org.openjdk.jmh.runner.options.Options;
4648
import org.openjdk.jmh.runner.options.OptionsBuilder;
4749
import software.amazon.awssdk.benchmark.apicall.httpclient.SdkHttpClientBenchmark;
4850
import software.amazon.awssdk.benchmark.utils.MockServer;
51+
import software.amazon.awssdk.core.ResponseBytes;
52+
import software.amazon.awssdk.core.sync.RequestBody;
53+
import software.amazon.awssdk.core.sync.ResponseTransformer;
4954
import software.amazon.awssdk.http.SdkHttpClient;
5055
import software.amazon.awssdk.http.apache.ApacheHttpClient;
56+
import software.amazon.awssdk.http.apache5.Apache5HttpClient;
5157
import software.amazon.awssdk.regions.Region;
5258
import software.amazon.awssdk.services.protocolrestjson.ProtocolRestJsonClient;
59+
import software.amazon.awssdk.services.protocolrestjson.model.StreamingInputOperationRequest;
60+
import software.amazon.awssdk.services.protocolrestjson.model.StreamingOutputOperationRequest;
61+
import software.amazon.awssdk.services.protocolrestjson.model.StreamingOutputOperationResponse;
5362

5463
/**
55-
* Benchmarking for running with different http clients.
64+
* Benchmarking for running with different Apache HTTP clients.
5665
*/
5766
@State(Scope.Benchmark)
5867
@Warmup(iterations = 3, time = 15, timeUnit = TimeUnit.SECONDS)
@@ -61,6 +70,19 @@
6170
@BenchmarkMode(Mode.Throughput)
6271
public class ApacheHttpClientBenchmark implements SdkHttpClientBenchmark {
6372

73+
private static final int STREAM_SIZE = 1024 * 1024; // 1MB
74+
private static final byte[] STREAM_DATA = new byte[STREAM_SIZE];
75+
76+
static {
77+
// Initialize stream data
78+
for (int i = 0; i < STREAM_SIZE; i++) {
79+
STREAM_DATA[i] = (byte) (i % 256);
80+
}
81+
}
82+
83+
@Param({"apache4", "apache5"})
84+
private String clientType;
85+
6486
private MockServer mockServer;
6587
private SdkHttpClient sdkHttpClient;
6688
private ProtocolRestJsonClient client;
@@ -70,8 +92,21 @@ public class ApacheHttpClientBenchmark implements SdkHttpClientBenchmark {
7092
public void setup() throws Exception {
7193
mockServer = new MockServer();
7294
mockServer.start();
73-
sdkHttpClient = ApacheHttpClient.builder()
74-
.buildWithDefaults(trustAllTlsAttributeMapBuilder().build());
95+
96+
// Create HTTP client based on parameter
97+
switch (clientType) {
98+
case "apache4":
99+
sdkHttpClient = ApacheHttpClient.builder()
100+
.buildWithDefaults(trustAllTlsAttributeMapBuilder().build());
101+
break;
102+
case "apache5":
103+
sdkHttpClient = Apache5HttpClient.builder()
104+
.buildWithDefaults(trustAllTlsAttributeMapBuilder().build());
105+
break;
106+
default:
107+
throw new IllegalArgumentException("Unknown client type: " + clientType);
108+
}
109+
75110
client = ProtocolRestJsonClient.builder()
76111
.endpointOverride(mockServer.getHttpsUri())
77112
.httpClient(sdkHttpClient)
@@ -109,12 +144,78 @@ public void concurrentApiCall(Blackhole blackhole) {
109144
awaitCountdownLatchUninterruptibly(countDownLatch, 10, TimeUnit.SECONDS);
110145
}
111146

112-
public static void main(String... args) throws Exception {
147+
@Benchmark
148+
@Override
149+
public void streamingPutOperation(Blackhole blackhole) {
150+
StreamingInputOperationRequest request = StreamingInputOperationRequest.builder()
151+
.build();
152+
RequestBody requestBody = RequestBody.fromBytes(STREAM_DATA);
153+
154+
blackhole.consume(client.streamingInputOperation(request, requestBody));
155+
}
156+
157+
@Benchmark
158+
@Override
159+
@OperationsPerInvocation(CONCURRENT_CALLS)
160+
public void concurrentStreamingPutOperation(Blackhole blackhole) {
161+
CountDownLatch countDownLatch = new CountDownLatch(CONCURRENT_CALLS);
113162

163+
for (int i = 0; i < CONCURRENT_CALLS; i++) {
164+
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
165+
StreamingInputOperationRequest request = StreamingInputOperationRequest.builder()
166+
.build();
167+
RequestBody requestBody = RequestBody.fromBytes(STREAM_DATA);
168+
client.streamingInputOperation(request, requestBody);
169+
}, executorService);
170+
171+
countDownUponCompletion(blackhole, future, countDownLatch);
172+
}
173+
174+
awaitCountdownLatchUninterruptibly(countDownLatch, 10, TimeUnit.SECONDS);
175+
}
176+
177+
@Benchmark
178+
@Override
179+
public void streamingOutputOperation(Blackhole blackhole) {
180+
StreamingOutputOperationRequest request = StreamingOutputOperationRequest.builder()
181+
.build();
182+
183+
ResponseBytes<StreamingOutputOperationResponse> responseBytes =
184+
client.streamingOutputOperation(request, ResponseTransformer.toBytes());
185+
186+
blackhole.consume(responseBytes.asByteArray());
187+
}
188+
189+
@Benchmark
190+
@Override
191+
@OperationsPerInvocation(CONCURRENT_CALLS)
192+
public void concurrentStreamingOutputOperation(Blackhole blackhole) {
193+
CountDownLatch countDownLatch = new CountDownLatch(CONCURRENT_CALLS);
194+
195+
for (int i = 0; i < CONCURRENT_CALLS; i++) {
196+
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
197+
StreamingOutputOperationRequest request = StreamingOutputOperationRequest.builder()
198+
.build();
199+
200+
ResponseBytes<StreamingOutputOperationResponse> responseBytes =
201+
client.streamingOutputOperation(request, ResponseTransformer.toBytes());
202+
203+
blackhole.consume(responseBytes.asByteArray());
204+
}, executorService);
205+
206+
countDownUponCompletion(blackhole, future, countDownLatch);
207+
}
208+
209+
awaitCountdownLatchUninterruptibly(countDownLatch, 10, TimeUnit.SECONDS);
210+
}
211+
212+
public static void main(String... args) throws Exception {
114213
Options opt = new OptionsBuilder()
115-
.include(ApacheHttpClientBenchmark.class.getSimpleName() + ".concurrentApiCall")
214+
.include(ApacheHttpClientBenchmark.class.getSimpleName())
116215
.addProfiler(StackProfiler.class)
216+
.addProfiler(GCProfiler.class)
117217
.build();
218+
118219
Collection<RunResult> run = new Runner(opt).run();
119220
}
120221
}

test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/utils/MockServer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public MockServer() throws IOException {
5959
server.setConnectors(new Connector[] {connector, sslConnector});
6060

6161
ServletContextHandler context = new ServletContextHandler(server, "/", ServletContextHandler.SESSIONS);
62-
context.addServlet(new ServletHolder(new AlwaysSuccessServlet()), "/*");
62+
context.addServlet(new ServletHolder(new StreamingMockServlet()), "/*");
6363
server.setHandler(context);
6464
}
6565

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.benchmark.utils;
17+
18+
import java.io.IOException;
19+
import java.io.InputStream;
20+
import java.io.OutputStream;
21+
import java.io.PrintWriter;
22+
import javax.servlet.http.HttpServlet;
23+
import javax.servlet.http.HttpServletRequest;
24+
import javax.servlet.http.HttpServletResponse;
25+
26+
public class StreamingMockServlet extends HttpServlet {
27+
private static final byte[] STREAMING_RESPONSE_DATA = new byte[1024 * 1024]; // 1MB response
28+
29+
static {
30+
// Initialize response data
31+
for (int i = 0; i < STREAMING_RESPONSE_DATA.length; i++) {
32+
STREAMING_RESPONSE_DATA[i] = (byte) (i % 256);
33+
}
34+
}
35+
36+
@Override
37+
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
38+
handleRequest(request, response);
39+
}
40+
41+
@Override
42+
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
43+
handleRequest(request, response);
44+
}
45+
46+
@Override
47+
protected void doPut(HttpServletRequest request, HttpServletResponse response) throws IOException {
48+
handleRequest(request, response);
49+
}
50+
51+
private void handleRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
52+
// Check if this should be a streaming response
53+
if (isStreamingOperation(request)) {
54+
handleStreamingRequest(request, response);
55+
} else {
56+
handleJsonRequest(request, response);
57+
}
58+
}
59+
60+
private boolean isStreamingOperation(HttpServletRequest request) {
61+
String uri = request.getRequestURI();
62+
String contentType = request.getContentType();
63+
64+
return uri.contains("streaming") ||
65+
uri.contains("StreamingInput") ||
66+
uri.contains("StreamingOutput") ||
67+
"application/octet-stream".equals(contentType);
68+
}
69+
70+
private void handleStreamingRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
71+
72+
// Consume input stream if present
73+
try (InputStream inputStream = request.getInputStream()) {
74+
byte[] buffer = new byte[8192];
75+
while (inputStream.read(buffer) != -1) {
76+
// Just consume the data
77+
}
78+
}
79+
80+
// Send streaming response
81+
response.setStatus(HttpServletResponse.SC_OK);
82+
response.setContentType("application/octet-stream");
83+
response.setContentLength(STREAMING_RESPONSE_DATA.length);
84+
response.setHeader("x-amz-request-id", "streaming-" + System.currentTimeMillis());
85+
86+
try (OutputStream outputStream = response.getOutputStream()) {
87+
outputStream.write(STREAMING_RESPONSE_DATA);
88+
outputStream.flush();
89+
}
90+
}
91+
92+
private void handleJsonRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
93+
94+
response.setStatus(HttpServletResponse.SC_OK);
95+
response.setContentType("application/json");
96+
response.setCharacterEncoding("UTF-8");
97+
response.setHeader("x-amz-request-id", "json-" + System.currentTimeMillis());
98+
99+
String jsonResponse = "{"
100+
+ "\"status\":\"success\","
101+
+ "\"message\":\"Mock operation completed\","
102+
+ "\"ResponseMetadata\":{"
103+
+ "\"RequestId\":\"mock-request-id\""
104+
+ "}"
105+
+ "}";
106+
107+
try (PrintWriter writer = response.getWriter()) {
108+
writer.write(jsonResponse);
109+
writer.flush();
110+
}
111+
}
112+
}

0 commit comments

Comments
 (0)