0
# Connection Pooling
1
2
The connection pooling capability provides multiple connection pool strategies for optimizing connection reuse and performance, including duplex, multiplex, round-robin, and random selection pools with comprehensive connection lifecycle management.
3
4
## ConnectionPool Interface
5
6
The base interface for all connection pool implementations.
7
8
```java { .api }
9
public interface ConnectionPool extends Closeable {
10
// Connection acquisition and release
11
CompletableFuture<Connection> acquire(boolean create);
12
boolean release(Connection connection);
13
boolean remove(Connection connection);
14
15
// Pool management
16
void close();
17
boolean isClosed();
18
19
// Pool statistics
20
int getConnectionCount();
21
int getIdleConnectionCount();
22
int getActiveConnectionCount();
23
24
// Pool configuration
25
int getMaxConnectionCount();
26
27
// Preconnection
28
CompletableFuture<Void> preCreateConnections(int connectionCount);
29
}
30
```
31
32
## DuplexConnectionPool
33
34
Connection pool for HTTP/1.1 duplex connections where each connection can handle one request at a time.
35
36
### DuplexConnectionPool Class
37
38
```java { .api }
39
public class DuplexConnectionPool extends AbstractConnectionPool {
40
public DuplexConnectionPool(Destination destination, int maxConnections, Callback requester);
41
public DuplexConnectionPool(Destination destination, int maxConnections, boolean cache, Callback requester);
42
43
// Configuration
44
public boolean isCache();
45
public int getMaxDuplexCount();
46
}
47
```
48
49
### Usage Examples
50
51
```java
52
// Configure HttpClient with duplex connection pool
53
HttpClient client = new HttpClient();
54
client.start();
55
56
// Default connection pool settings
57
// - Max connections per destination: typically 64
58
// - Connection caching: enabled
59
// - Suitable for HTTP/1.1 connections
60
61
// Make concurrent requests - each uses separate connection
62
List<CompletableFuture<ContentResponse>> futures = new ArrayList<>();
63
for (int i = 0; i < 10; i++) {
64
CompletableFuture<ContentResponse> future = client.newRequest("https://api.example.com/data/" + i).send();
65
futures.add(future);
66
}
67
68
// Wait for all requests to complete
69
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
70
.thenRun(() -> {
71
System.out.println("All requests completed");
72
futures.forEach(future -> {
73
try {
74
ContentResponse response = future.get();
75
System.out.println("Response: " + response.getStatus());
76
} catch (Exception e) {
77
System.err.println("Request failed: " + e.getMessage());
78
}
79
});
80
});
81
```
82
83
## MultiplexConnectionPool
84
85
Connection pool for HTTP/2 multiplex connections where each connection can handle multiple concurrent requests.
86
87
### MultiplexConnectionPool Class
88
89
```java { .api }
90
public class MultiplexConnectionPool extends AbstractConnectionPool {
91
public MultiplexConnectionPool(Destination destination, int maxConnections, Callback requester, int maxMultiplex);
92
93
// Configuration
94
public int getMaxMultiplex();
95
}
96
```
97
98
### Usage Examples
99
100
```java
101
// Configure HttpClient for HTTP/2 with multiplex connection pool
102
HttpClient client = new HttpClient();
103
104
// Enable HTTP/2
105
client.setProtocols(List.of("h2", "http/1.1"));
106
client.start();
107
108
// HTTP/2 connections can multiplex many requests over single connection
109
// Default max multiplex: typically 1024 streams per connection
110
111
// Make many concurrent requests over fewer connections
112
List<CompletableFuture<ContentResponse>> futures = new ArrayList<>();
113
for (int i = 0; i < 100; i++) {
114
CompletableFuture<ContentResponse> future = client.newRequest("https://http2.example.com/api/data/" + i).send();
115
futures.add(future);
116
}
117
118
// All requests may use the same HTTP/2 connection with multiplexing
119
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
120
.thenRun(() -> System.out.println("All HTTP/2 requests completed"));
121
```
122
123
## RoundRobinConnectionPool
124
125
Connection pool that distributes requests across available connections in round-robin fashion.
126
127
### RoundRobinConnectionPool Class
128
129
```java { .api }
130
public class RoundRobinConnectionPool extends AbstractConnectionPool {
131
public RoundRobinConnectionPool(Destination destination, int maxConnections, Callback requester);
132
public RoundRobinConnectionPool(Destination destination, int maxConnections, Callback requester, int maxMultiplex);
133
}
134
```
135
136
### Usage Examples
137
138
```java
139
// Round-robin is useful for load balancing across multiple connections
140
// Typically used with HTTP/1.1 where you want to distribute load evenly
141
142
public class RoundRobinClient {
143
private final HttpClient client;
144
145
public RoundRobinClient() throws Exception {
146
this.client = new HttpClient();
147
148
// Configure connection factory to use round-robin pool
149
// Note: Direct pool configuration is typically done at transport level
150
151
client.start();
152
}
153
154
public void makeBalancedRequests() throws Exception {
155
// Make requests that will be distributed round-robin across connections
156
for (int i = 0; i < 20; i++) {
157
final int requestId = i;
158
client.newRequest("https://api.example.com/endpoint/" + i)
159
.send(result -> {
160
if (result.isSucceeded()) {
161
System.out.println("Request " + requestId + " completed on connection: " +
162
result.getRequest().getConnection());
163
}
164
});
165
}
166
}
167
}
168
```
169
170
## RandomConnectionPool
171
172
Connection pool that randomly selects from available connections.
173
174
### RandomConnectionPool Class
175
176
```java { .api }
177
public class RandomConnectionPool extends AbstractConnectionPool {
178
public RandomConnectionPool(Destination destination, int maxConnections, Callback requester);
179
public RandomConnectionPool(Destination destination, int maxConnections, Callback requester, int maxMultiplex);
180
}
181
```
182
183
### Usage Examples
184
185
```java
186
// Random selection can help avoid hot-spotting on specific connections
187
// Useful when you want to distribute load unpredictably
188
189
public class RandomizedLoadClient {
190
public void demonstrateRandomPool() {
191
// Random connection selection helps with:
192
// - Avoiding connection hot-spots
193
// - Better distribution in some network topologies
194
// - Testing resilience across different connections
195
196
// Requests will be randomly distributed across available connections
197
for (int i = 0; i < 50; i++) {
198
client.GET("https://distributed.example.com/api/data");
199
}
200
}
201
}
202
```
203
204
## ValidatingConnectionPool
205
206
Connection pool that validates connections before use to ensure they are still functional.
207
208
### ValidatingConnectionPool Class
209
210
```java { .api }
211
public class ValidatingConnectionPool extends DuplexConnectionPool {
212
public ValidatingConnectionPool(Destination destination, int maxConnections, Callback requester);
213
214
// Validation configuration
215
public void setValidationTimeout(long validationTimeout);
216
public long getValidationTimeout();
217
}
218
```
219
220
### Usage Examples
221
222
```java
223
// Validating pool is useful for long-lived connections that might become stale
224
// Automatically validates connections before reuse
225
226
public class ValidatedClient {
227
public void configureValidation() throws Exception {
228
HttpClient client = new HttpClient();
229
230
// Configuration for connection validation
231
// Validates connections that have been idle for a certain period
232
client.setIdleTimeout(30000); // 30 seconds idle timeout
233
234
client.start();
235
236
// Long pause between requests to demonstrate validation
237
ContentResponse response1 = client.GET("https://api.example.com/data");
238
System.out.println("First request: " + response1.getStatus());
239
240
// Wait longer than idle timeout
241
Thread.sleep(35000);
242
243
// Next request will validate/recreate connection if needed
244
ContentResponse response2 = client.GET("https://api.example.com/data");
245
System.out.println("Second request: " + response2.getStatus());
246
247
client.stop();
248
}
249
}
250
```
251
252
## Connection Pool Configuration
253
254
### Per-Destination Pool Settings
255
256
```java
257
public class PoolConfigurationExample {
258
public void configureConnectionPools() throws Exception {
259
HttpClient client = new HttpClient();
260
261
// Configure maximum connections per destination
262
client.setMaxConnectionsPerDestination(20);
263
264
// Configure request queue size per destination
265
client.setMaxRequestsQueuedPerDestination(50);
266
267
// Configure connection idle timeout
268
client.setIdleTimeout(60000); // 60 seconds
269
270
// Configure connection establishment timeout
271
client.setConnectTimeout(10000); // 10 seconds
272
273
client.start();
274
275
// These settings affect all connection pools for this client
276
System.out.println("Max connections per destination: " + client.getMaxConnectionsPerDestination());
277
System.out.println("Idle timeout: " + client.getIdleTimeout());
278
}
279
}
280
```
281
282
### Custom Connection Pool Factory
283
284
```java
285
public class CustomConnectionPoolFactory {
286
public static ConnectionPool createCustomPool(Destination destination, int maxConnections) {
287
// Create a custom connection pool based on requirements
288
289
if (destination.getScheme().equals("https") && supportsHttp2(destination)) {
290
// Use multiplex pool for HTTP/2 HTTPS connections
291
return new MultiplexConnectionPool(destination, maxConnections, null, 100);
292
} else if (isHighVolumeDestination(destination)) {
293
// Use round-robin for high-volume destinations
294
return new RoundRobinConnectionPool(destination, maxConnections, null);
295
} else if (isUnreliableNetwork(destination)) {
296
// Use validating pool for unreliable networks
297
return new ValidatingConnectionPool(destination, maxConnections, null);
298
} else {
299
// Default to duplex pool
300
return new DuplexConnectionPool(destination, maxConnections, null);
301
}
302
}
303
304
private static boolean supportsHttp2(Destination destination) {
305
// Logic to determine if destination supports HTTP/2
306
return true; // Simplified
307
}
308
309
private static boolean isHighVolumeDestination(Destination destination) {
310
// Logic to identify high-volume destinations
311
return destination.getHost().contains("api") || destination.getHost().contains("cdn");
312
}
313
314
private static boolean isUnreliableNetwork(Destination destination) {
315
// Logic to identify destinations with unreliable connections
316
return destination.getHost().contains("mobile") || destination.getHost().contains("satellite");
317
}
318
}
319
```
320
321
## Connection Pool Monitoring
322
323
### Pool Statistics
324
325
```java
326
public class ConnectionPoolMonitor {
327
private final HttpClient client;
328
329
public ConnectionPoolMonitor(HttpClient client) {
330
this.client = client;
331
}
332
333
public void printPoolStatistics() {
334
// Note: Direct access to connection pools requires internal APIs
335
// This is conceptual - actual implementation may vary
336
337
System.out.println("Connection Pool Statistics:");
338
System.out.println("Max connections per destination: " + client.getMaxConnectionsPerDestination());
339
System.out.println("Current destinations: " + getDestinationCount());
340
341
// Per-destination statistics would require accessing internal destination manager
342
printDestinationStats();
343
}
344
345
private void printDestinationStats() {
346
// Conceptual implementation for monitoring
347
System.out.println("Destination Statistics:");
348
System.out.println(" api.example.com: 5 active, 3 idle connections");
349
System.out.println(" cdn.example.com: 2 active, 8 idle connections");
350
}
351
352
private int getDestinationCount() {
353
// Would access internal destination manager
354
return 0; // Placeholder
355
}
356
357
public void scheduleMonitoring(ScheduledExecutorService scheduler) {
358
scheduler.scheduleAtFixedRate(this::printPoolStatistics, 0, 30, TimeUnit.SECONDS);
359
}
360
}
361
```
362
363
### Connection Lifecycle Monitoring
364
365
```java
366
public class ConnectionLifecycleMonitor {
367
public void monitorConnections(HttpClient client) {
368
// Add request listeners to monitor connection usage
369
client.getRequestListeners().addListener(new Request.Listener() {
370
@Override
371
public void onBegin(Request request) {
372
Connection connection = request.getConnection();
373
if (connection != null) {
374
System.out.println("Request started on connection: " + connection);
375
}
376
}
377
378
@Override
379
public void onSuccess(Request request) {
380
Connection connection = request.getConnection();
381
if (connection != null) {
382
System.out.println("Request completed on connection: " + connection);
383
}
384
}
385
});
386
}
387
}
388
```
389
390
## Advanced Pool Management
391
392
### Pool Preheating
393
394
```java
395
public class PoolPreheating {
396
public void preheatConnections(HttpClient client, String... urls) throws Exception {
397
List<CompletableFuture<Void>> preheatFutures = new ArrayList<>();
398
399
for (String url : urls) {
400
// Make lightweight requests to establish connections
401
CompletableFuture<Void> future = client.newRequest(url)
402
.method(HttpMethod.HEAD) // Use HEAD to minimize data transfer
403
.send()
404
.thenApply(response -> null); // Convert to Void
405
406
preheatFutures.add(future);
407
}
408
409
// Wait for all preheat requests to complete
410
CompletableFuture.allOf(preheatFutures.toArray(new CompletableFuture[0]))
411
.get(30, TimeUnit.SECONDS);
412
413
System.out.println("Connection pools preheated for " + urls.length + " destinations");
414
}
415
}
416
417
// Usage
418
PoolPreheating preheater = new PoolPreheating();
419
preheater.preheatConnections(client,
420
"https://api.example.com",
421
"https://cdn.example.com",
422
"https://auth.example.com"
423
);
424
```
425
426
### Dynamic Pool Sizing
427
428
```java
429
public class DynamicPoolManager {
430
private final HttpClient client;
431
private final Map<String, Integer> destinationLoad;
432
433
public DynamicPoolManager(HttpClient client) {
434
this.client = client;
435
this.destinationLoad = new ConcurrentHashMap<>();
436
}
437
438
public void adjustPoolSizes() {
439
destinationLoad.forEach((destination, load) -> {
440
int recommendedSize = calculateOptimalPoolSize(load);
441
adjustPoolSize(destination, recommendedSize);
442
});
443
}
444
445
private int calculateOptimalPoolSize(int load) {
446
// Calculate optimal pool size based on load
447
if (load > 100) return 50;
448
if (load > 50) return 25;
449
if (load > 10) return 10;
450
return 5;
451
}
452
453
private void adjustPoolSize(String destination, int size) {
454
// Conceptual - actual implementation would require internal APIs
455
System.out.println("Adjusting pool size for " + destination + " to " + size);
456
}
457
458
public void recordRequest(String destination) {
459
destinationLoad.merge(destination, 1, Integer::sum);
460
}
461
462
public void scheduleOptimization(ScheduledExecutorService scheduler) {
463
scheduler.scheduleAtFixedRate(this::adjustPoolSizes, 0, 60, TimeUnit.SECONDS);
464
}
465
}
466
```
467
468
## Connection Pool Best Practices
469
470
### Optimal Configuration
471
472
```java
473
public class PoolBestPractices {
474
public HttpClient createOptimalClient() throws Exception {
475
HttpClient client = new HttpClient();
476
477
// Conservative connection limits to avoid overwhelming servers
478
client.setMaxConnectionsPerDestination(20);
479
client.setMaxRequestsQueuedPerDestination(100);
480
481
// Reasonable timeouts
482
client.setConnectTimeout(10000); // 10 seconds
483
client.setIdleTimeout(60000); // 60 seconds
484
485
// Enable connection keep-alive
486
client.setTCPNoDelay(true);
487
488
// Configure for HTTP/2 when available
489
client.setProtocols(List.of("h2", "http/1.1"));
490
491
client.start();
492
return client;
493
}
494
495
public void demonstrateEfficientUsage(HttpClient client) throws Exception {
496
// Reuse client across multiple requests for connection pooling benefits
497
List<CompletableFuture<ContentResponse>> futures = new ArrayList<>();
498
499
// Make multiple requests to same destination - will reuse connections
500
for (int i = 0; i < 10; i++) {
501
CompletableFuture<ContentResponse> future = client.newRequest("https://api.example.com/data/" + i).send();
502
futures.add(future);
503
}
504
505
// Process responses as they complete
506
for (CompletableFuture<ContentResponse> future : futures) {
507
future.thenAccept(response -> {
508
System.out.println("Response: " + response.getStatus());
509
// Connection automatically returned to pool after response processing
510
});
511
}
512
513
// Don't stop client until all operations are complete
514
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
515
}
516
}
517
```
518
519
### Resource Management
520
521
```java
522
public class ResourceManagedClient implements AutoCloseable {
523
private final HttpClient client;
524
525
public ResourceManagedClient() throws Exception {
526
this.client = new HttpClient();
527
configureClient();
528
client.start();
529
}
530
531
private void configureClient() {
532
// Optimize for connection reuse
533
client.setMaxConnectionsPerDestination(15);
534
client.setIdleTimeout(30000);
535
536
// Add shutdown hook for graceful cleanup
537
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
538
try {
539
close();
540
} catch (Exception e) {
541
System.err.println("Error during client shutdown: " + e.getMessage());
542
}
543
}));
544
}
545
546
public ContentResponse get(String url) throws Exception {
547
return client.GET(url);
548
}
549
550
@Override
551
public void close() throws Exception {
552
// Graceful shutdown - allows existing requests to complete
553
client.stop();
554
}
555
}
556
557
// Usage with try-with-resources
558
try (ResourceManagedClient client = new ResourceManagedClient()) {
559
ContentResponse response = client.get("https://api.example.com/data");
560
System.out.println("Response: " + response.getStatus());
561
} // Automatically closes and cleans up connection pools
562
```