0

We are trying to connect to a ClickHouse cluster (containing 4 nodes and 3 ClickHouse-keepers) using the JDBC connector. When I test the performance with 100, 200, or 300 threads (users), after some time (~5 minutes), I encounter connection read timeout errors (in production environment) or "Address already in use" errors (in local environment) although nothing is in use.

Currently, I have three tables:

  • main_table
  • replication_table (2 shards, 2 replicas per shard)
  • buffer_table (to mitigate "too many parts" errors)

Data is first inserted into the buffer_table, which then flushes out to the replicated_table, from where the data is distributed to all the replicas (4 nodes, depending on the shard key).

Here is the configuration used while connecting:

@Value("${clickhouse.datasource.url}")
private String url;

@Value("${clickhouse.datasource.username}")
private String username;

@Value("${clickhouse.datasource.password}")
private String password;

@Value("${clickhouse.datasource.driver-class-name}")
private String driverClass;

@Value("${clickhouse.datasource.connection-timeout}")
private String connectionTimeout;

@Value("${clickhouse.datasource.socket-timeout}")
private String socketTimeout;

@Value("${clickhouse.datasource.ssl}")
private String ssl;

@Value("${clickhouse.datasource.load-balancing-policy}")
private String loadBalancingPolicy;

@Bean
public DataSource dataSource() throws SQLException {
    Properties properties = new Properties();
    properties.setProperty("user", username.trim());
    properties.setProperty("password", password.trim());
    properties.setProperty("connection_timeout", connectionTimeout.trim());
    properties.setProperty("socket_timeout", socketTimeout.trim());
    properties.setProperty("ssl", ssl.trim());
    properties.setProperty("load_balancing_policy", loadBalancingPolicy.trim());

    ClickHouseDataSource dataSource = new ClickHouseDataSource(url.trim(), properties);
    return dataSource;
}

Configuration properties:

spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.minimum-idle=200
spring.datasource.hikari.maximum-pool-size=200
spring.datasource.hikari.idle-timeout=600000
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.auto-commit=true

clickhouse.datasource.url=jdbc:clickhouse://server1:8123,server2:8123,server3:8123,server4:8123/dap_dev
clickhouse.datasource.driver-class-name=com.clickhouse.jdbc.ClickHouseDriver
clickhouse.datasource.connection-timeout=30000
clickhouse.datasource.socket-timeout=300000
clickhouse.datasource.ssl=false
clickhouse.datasource.load-balancing-policy=roundRobin

Please let me know if there is any property or something else I am doing wrong that is causing ClickHouse to throw these timeout errors.

3
  • Hi Shivan - could you please explain why you are using so many concurrent threads? ClickHouse works best using large batch sizes (10000+ rows per INSERT) - each individual INSERT thread will result in 1 part. This is likely the cause of TOO_MANY_PARTS, and probably in turn causing performance bottlenecks due to parts merging too slowly. My recommendation would be to first reduce to lower number of threads to 1 or 10, and then can reuse threads for multiple queries: clickhouse.com/docs/en/integrations/java#multiple-queries - should also evaluate server performance via Advanced Dashboard Commented Jul 24, 2024 at 16:12
  • Hi @ThomO'Connor In our scenario, there are very frequent writes, and we aim to achieve at least 200 TPS. For batch insertion, I'm using a buffer table where we buffer around 10,000 rows, thus resolving the parts problem. However, the issue now lies with the JDBC connection. After 2-3 minutes, it reports a connection timeout. I initially thought the issue was due to an insufficient number of threads, so I increased the threads handling the service-side hits, but the problem persists. Commented Jul 25, 2024 at 5:13
  • I see, thanks for explaining Shivan. It is a good idea to reuse each thread some, so using a connection pool and maintaining a set of established connections is a good idea. This reduces the number of new connections that must be established (TCP overhead is significant if opening/closing the connection every time). However, if the connection is idle, it can timeout - some users will reuse a connection for a defined number of INSERTs or queries, for example 10, then close & reopen that connection - this method provides a good balance of reuse while making sure connections are not left open Commented Sep 18, 2024 at 20:11

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.