Skip to content

Commit 82f8b21

Browse files
authored
Merge pull request #1766 from ClickHouse/clientv2_connection_pooling
[client-v2] Connection pool configuration
2 parents 2a41352 + d4ad2cc commit 82f8b21

File tree

5 files changed

+399
-61
lines changed

5 files changed

+399
-61
lines changed

client-v2/src/main/java/com/clickhouse/client/api/Client.java

Lines changed: 109 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,14 @@
3939
import com.clickhouse.client.config.ClickHouseClientOption;
4040
import com.clickhouse.client.config.ClickHouseDefaults;
4141
import com.clickhouse.client.http.ClickHouseHttpProto;
42+
import com.clickhouse.client.http.config.ClickHouseHttpOption;
4243
import com.clickhouse.data.ClickHouseColumn;
4344
import com.clickhouse.data.ClickHouseFormat;
4445
import com.clickhouse.data.format.BinaryStreamUtils;
46+
import org.apache.hc.client5.http.ConnectTimeoutException;
4547
import org.apache.hc.core5.concurrent.DefaultThreadFactory;
4648
import org.apache.hc.core5.http.ClassicHttpResponse;
49+
import org.apache.hc.core5.http.ConnectionRequestTimeoutException;
4750
import org.apache.hc.core5.http.HttpStatus;
4851
import org.apache.hc.core5.http.NoHttpResponseException;
4952
import org.slf4j.Logger;
@@ -220,17 +223,17 @@ public Builder() {
220223
public Builder addEndpoint(String endpoint) {
221224
try {
222225
URL endpointURL = new java.net.URL(endpoint);
223-
if (!(endpointURL.getProtocol().equalsIgnoreCase("https") ||
224-
endpointURL.getProtocol().equalsIgnoreCase("http"))) {
226+
227+
if (endpointURL.getProtocol().equalsIgnoreCase("https")) {
228+
addEndpoint(Protocol.HTTP, endpointURL.getHost(), endpointURL.getPort(), true);
229+
} else if (endpointURL.getProtocol().equalsIgnoreCase("http")) {
230+
addEndpoint(Protocol.HTTP, endpointURL.getHost(), endpointURL.getPort(), false);
231+
} else {
225232
throw new IllegalArgumentException("Only HTTP and HTTPS protocols are supported");
226233
}
227234
} catch (java.net.MalformedURLException e) {
228235
throw new IllegalArgumentException("Endpoint should be a valid URL string", e);
229236
}
230-
if (endpoint.startsWith("https://")) {
231-
this.configuration.put(ClickHouseClientOption.SSL.getKey(), "true");
232-
}
233-
this.endpoints.add(endpoint);
234237
return this;
235238
}
236239

@@ -252,7 +255,7 @@ public Builder addEndpoint(Protocol protocol, String host, int port, boolean sec
252255
this.configuration.put(ClickHouseClientOption.SSL.getKey(), "true");
253256
}
254257
String endpoint = String.format("%s%s://%s:%d", protocol.toString().toLowerCase(), secure ? "s": "", host, port);
255-
this.addEndpoint(endpoint);
258+
this.endpoints.add(endpoint);
256259
return this;
257260
}
258261

@@ -302,7 +305,15 @@ public Builder setAccessToken(String accessToken) {
302305
return this;
303306
}
304307

305-
// SOCKET SETTINGS
308+
/**
309+
* Configures client to use build-in connection pool
310+
* @param enable - if connection pool should be enabled
311+
* @return
312+
*/
313+
public Builder enableConnectionPool(boolean enable) {
314+
this.configuration.put("connection_pool_enabled", String.valueOf(enable));
315+
return this;
316+
}
306317

307318
/**
308319
* Default connection timeout in milliseconds. Timeout is applied to establish a connection.
@@ -324,6 +335,72 @@ public Builder setConnectTimeout(long timeout, ChronoUnit unit) {
324335
return this.setConnectTimeout(Duration.of(timeout, unit).toMillis());
325336
}
326337

338+
/**
339+
* Set timeout for waiting a free connection from a pool when all connections are leased.
340+
* This configuration is important when need to fail fast in high concurrent scenarios.
341+
* Default is 10 s.
342+
* @param timeout - connection timeout in milliseconds
343+
* @param unit - time unit
344+
*/
345+
public Builder setConnectionRequestTimeout(long timeout, ChronoUnit unit) {
346+
this.configuration.put("connection_request_timeout", String.valueOf(Duration.of(timeout, unit).toMillis()));
347+
return this;
348+
}
349+
350+
/**
351+
* Sets the maximum number of connections that can be opened at the same time to a single server. Limit is not
352+
* a hard stop. It is done to prevent threads stuck inside a connection pool waiting for a connection.
353+
* Default is 10. It is recommended to set a higher value for a high concurrent applications. It will let
354+
* more threads to get a connection and execute a query.
355+
*
356+
* @param maxConnections - maximum number of connections
357+
*/
358+
public Builder setMaxConnections(int maxConnections) {
359+
this.configuration.put(ClickHouseHttpOption.MAX_OPEN_CONNECTIONS.getKey(), String.valueOf(maxConnections));
360+
return this;
361+
}
362+
363+
/**
364+
* Sets how long any connection would be considered as active and able for a lease.
365+
* After this time connection will be marked for sweep and will not be returned from a pool.
366+
* Has more effect than keep-alive timeout.
367+
* @param timeout - time in unit
368+
* @param unit - time unit
369+
* @return
370+
*/
371+
public Builder setConnectionTTL(long timeout, ChronoUnit unit) {
372+
this.configuration.put(ClickHouseClientOption.CONNECTION_TTL.getKey(), String.valueOf(Duration.of(timeout, unit).toMillis()));
373+
return this;
374+
}
375+
376+
/**
377+
* Sets keep alive timeout for a connection to override server value. If set to -1 then server value will be used.
378+
* Default is -1.
379+
* Doesn't override connection TTL value.
380+
* {@see Client#setConnectionTTL}
381+
* @param timeout - time in unit
382+
* @param unit - time unit
383+
* @return
384+
*/
385+
public Builder setKeepAliveTimeout(long timeout, ChronoUnit unit) {
386+
this.configuration.put(ClickHouseHttpOption.KEEP_ALIVE_TIMEOUT.getKey(), String.valueOf(Duration.of(timeout, unit).toMillis()));
387+
return this;
388+
}
389+
390+
/**
391+
* Sets strategy of how connections are reuse.
392+
* Default is {@link ConnectionReuseStrategy#FIFO} to evenly distribute load between them.
393+
*
394+
* @param strategy - strategy for connection reuse
395+
* @return
396+
*/
397+
public Builder setConnectionReuseStrategy(ConnectionReuseStrategy strategy) {
398+
this.configuration.put("connection_reuse_strategy", strategy.name());
399+
return this;
400+
}
401+
402+
// SOCKET SETTINGS
403+
327404
/**
328405
* Default socket timeout in milliseconds. Timeout is applied to read and write operations.
329406
*
@@ -485,8 +562,8 @@ public Builder setProxyCredentials(String user, String pass) {
485562
* @param timeUnit
486563
* @return
487564
*/
488-
public Builder setExecutionTimeout(long timeout, TimeUnit timeUnit) {
489-
this.configuration.put(ClickHouseClientOption.MAX_EXECUTION_TIME.getKey(), String.valueOf(timeUnit.toMillis(timeout)));
565+
public Builder setExecutionTimeout(long timeout, ChronoUnit timeUnit) {
566+
this.configuration.put(ClickHouseClientOption.MAX_EXECUTION_TIME.getKey(), String.valueOf(Duration.of(timeout, timeUnit).toMillis()));
490567
return this;
491568
}
492569

@@ -719,6 +796,26 @@ private Map<String, String> setDefaults(Map<String, String> userConfig) {
719796
userConfig.put(ClickHouseClientOption.ASYNC.getKey(), "false");
720797
}
721798

799+
if (!userConfig.containsKey(ClickHouseHttpOption.MAX_OPEN_CONNECTIONS.getKey())) {
800+
userConfig.put(ClickHouseHttpOption.MAX_OPEN_CONNECTIONS.getKey(), "10");
801+
}
802+
803+
if (!userConfig.containsKey("connection_request_timeout")) {
804+
userConfig.put("connection_request_timeout", "10000");
805+
}
806+
807+
if (!userConfig.containsKey("connection_reuse_strategy")) {
808+
userConfig.put("connection_reuse_strategy", ConnectionReuseStrategy.FIFO.name());
809+
}
810+
811+
if (!userConfig.containsKey("connection_pool_enabled")) {
812+
userConfig.put("connection_pool_enabled", "true");
813+
}
814+
815+
if (!userConfig.containsKey("connection_ttl")) {
816+
userConfig.put("connection_ttl", "-1");
817+
}
818+
722819
return userConfig;
723820
}
724821
}
@@ -1212,6 +1309,8 @@ public CompletableFuture<QueryResponse> query(String sqlQuery, Map<String, Objec
12121309
return new QueryResponse(httpResponse, finalSettings.getFormat(), finalSettings, metrics);
12131310
} catch (ClientException e) {
12141311
throw e;
1312+
} catch (ConnectionRequestTimeoutException | ConnectTimeoutException e) {
1313+
throw new ConnectionInitiationException("Failed to get connection", e);
12151314
} catch (Exception e) {
12161315
throw new ClientException("Failed to execute query", e);
12171316
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.clickhouse.client.api;
2+
3+
public enum ConnectionReuseStrategy {
4+
5+
/**
6+
* Reuse recently freed connection and returned to a pool
7+
*/
8+
LIFO,
9+
10+
/**
11+
* Reuse mostly all connections
12+
*/
13+
FIFO
14+
;
15+
}

0 commit comments

Comments
 (0)