diff --git a/databend-jdbc/src/main/java/com/databend/jdbc/DatabendConnection.java b/databend-jdbc/src/main/java/com/databend/jdbc/DatabendConnection.java index 3bc91b96..d653aed9 100644 --- a/databend-jdbc/src/main/java/com/databend/jdbc/DatabendConnection.java +++ b/databend-jdbc/src/main/java/com/databend/jdbc/DatabendConnection.java @@ -644,7 +644,7 @@ DatabendClient startQueryWithFailover(String sql, StageAttachment attach) throws sb.setStageAttachment(attach); } ClientSettings s = sb.build(); - logger.log(Level.FINE, "retry " + times + " times to execute query: " + sql + " on " + s.getHost()); + logger.log(Level.FINE, "retry " + i + " times to execute query: " + sql + " on " + s.getHost()); return new DatabendClientV1(httpClient, sql, s, this); } catch (RuntimeException e1) { e = e1; diff --git a/databend-jdbc/src/test/java/com/databend/jdbc/TestMultiHost.java b/databend-jdbc/src/test/java/com/databend/jdbc/TestMultiHost.java index c9390418..3a149eaf 100644 --- a/databend-jdbc/src/test/java/com/databend/jdbc/TestMultiHost.java +++ b/databend-jdbc/src/test/java/com/databend/jdbc/TestMultiHost.java @@ -13,6 +13,7 @@ public class TestMultiHost { private final String DEFAULT_JDBC_URL = "jdbc:databend://localhost:8000,localhost:8002,localhost:8003/default"; private final String RANDOM_JDBC_URL = "jdbc:databend://localhost:8000,localhost:8002,localhost:8003/default?load_balancing_policy=random"; private final String ROUND_ROBIN_JDBC_URL = "jdbc:databend://localhost:8000,localhost:8002,localhost:8003/default?load_balancing_policy=round_robin"; + private final String FAIL_OVER_JDBC_URL = "jdbc:databend://localhost:7222,localhost:7223,localhost:7224,localhost:8000/default?load_balancing_policy=round_robin&max_failover_retry=4"; private Connection createConnection(String url) throws SQLException { return DriverManager.getConnection(url, "databend", "databend"); @@ -115,4 +116,39 @@ public void testRoundRobinLoadBalancing() Assert.assertEquals(unknown, 0); Assert.assertEquals(node8000 + node8002 + node8003, 90); } + + @Test(groups = {"IT", "cluster"}) + public void testFailOver() + throws SQLException { + // try connect with three nodes 1000 times and count for each node + int node8000 = 0; + int node8002 = 0; + int node8003 = 0; + int unknown = 0; + for (int i = 0; i < 30; i++) { + try (Connection connection = createConnection(FAIL_OVER_JDBC_URL)) { + DatabendStatement statement = (DatabendStatement) connection.createStatement(); + // remove the effect setup commands + for (int j = 0; j < 3; j++) { + statement.execute("select value from system.configs where name = 'http_handler_port';"); + ResultSet r = statement.getResultSet(); + r.next(); + if (r.getInt(1) == 8000) { + node8000++; + } else if (r.getInt(1) == 8002) { + node8002++; + } else if (r.getInt(1) == 8003) { + node8003++; + } else { + unknown++; + } + } + } + } + System.out.println("node8000: " + node8000 + ", node8002: " + node8002 + ", node8003: " + node8003 + ", unknown: " + unknown); + + Assert.assertEquals(node8000, 90); + Assert.assertEquals(unknown, 0); + Assert.assertEquals(node8000 + node8002 + node8003, 90); + } } diff --git a/docs/Connection.md b/docs/Connection.md index f26aee28..140808cf 100644 --- a/docs/Connection.md +++ b/docs/Connection.md @@ -54,6 +54,40 @@ Then the above URL within warehouse DSN can be used as follows: Connection conn=DriverManager.getConnection(url); ``` +### Configure load balancing and failover + +Load balancing in Databend JDBC works by routing queries to different endpoints specified in the JDBC URL based on the chosen policy. This allows for better distribution of workload across multiple Databend nodes. + +#### Load Balancing Options + +There are three load balancing options available: + +1. **disabled**: Only routes queries to the first endpoint provided (sorted in alphabetic order). +2. **random**: Randomly distributes queries based on the query ID. +3. **round_robin**: Distributes queries evenly to each node in a circular order. + +#### Configurable Parameters + +| Parameter | Description | Default | Example | +|-----------|-------------|---------|---------| +| load_balancing_policy | Specifies the load balancing policy for multi-host connections. Options are "disabled", "random", and "round_robin". | disabled | jdbc:databend://localhost:8000,localhost:8002,localhost:8003/default?load_balancing_policy=random | +| max_failover_retry | Specifies the maximum number of retry attempts for failover connections. | 0 | jdbc:databend://localhost:7222,localhost:7223,localhost:7224,localhost:8000/default?max_failover_retry=4 | + +#### Examples + +1. Basic load balancing with round-robin policy: `jdbc:databend://localhost:8000,localhost:8002,localhost:8003/default?load_balancing_policy=round_robin` +2. Load balancing with random policy and failover configuration:: `jdbc:databend://localhost:8000,localhost:8002,localhost:8003/default?load_balancing_policy=random&max_failover_retry=3 +` +3. Load balancing with SSL enabled:`jdbc:databend://localhost:8000,localhost:8002,localhost:8003/default?ssl=true&load_balancing_policy=round_robin` + +**NOTICE:** + +When configuring SSL, it's recommended to use the approach shown in the last example, which allows for more detailed SSL configuration including certificate verification. + +Remember to replace the hostnames, ports, and file paths with your actual Databend cluster configuration and SSL certificate locations. + +Failover retry occur only for connection issues (java.net.ConnectException), other exception will NOT trigger retry + ## Connection parameters The driver supports various parameters that may be set as URL parameters or as properties passed to DriverManager. Both @@ -75,20 +109,22 @@ String url="jdbc:databend://databend:secret@0.0.0.0:8000/hello_databend"; ### Parameter References -| Parameter | Description | Default | example | -|------------------------|---------------------------------------------------------------------------------------------------------------------------|---------|-------------------------------------------------------------------------| -| user | Databend user name | none | jdbc:databend://0.0.0.0:8000/hello_databend?user=test | -| password | Databend user password | none | jdbc:databend://0.0.0.0:8000/hello_databend?password=secret | -| SSL | Enable SSL | false | jdbc:databend://0.0.0.0:8000/hello_databend?SSL=true | -| sslmode | SSL mode | disable | jdbc:databend://0.0.0.0:8000/hello_databend?sslmode=enable | -| copy_purge | If True, the command will purge the files in the stage after they are loaded successfully into the table | false | jdbc:databend://0.0.0.0:8000/hello_databend?copy_purge=true | -| presigned_url_disabled | whether use presigned url to upload data, generally if you use local disk as your storage layer, it should be set as true | false | jdbc:databend://0.0.0.0:8000/hello_databend?presigned_url_disabled=true | -| wait_time_secs | Restful query api blocking time, if the query is not finished, the api will block for wait_time_secs seconds | 10 | jdbc:databend://0.0.0.0:8000/hello_databend?wait_time_secs=10 | -| max_rows_in_buffer | the maximum rows in server session buffer | 5000000 | jdbc:databend://0.0.0.0:8000/hello_databend?max_rows_in_buffer=5000000 | -| max_rows_per_page | the maximum rows per page in response data body | 100000 | jdbc:databend://0.0.0.0:8000/default?max_rows_per_page=100000 | -| connection_timeout | okhttp connection_timeout param | 0 | jdbc:databend://0.0.0.0:8000/default?connection_timeout=100000 | -| query_timeout | time that you wait a SQL execution | 90 | jdbc:databend://0.0.0.0:8000/default?query_timeout=120 | -| null_display | null value display | \N | jdbc:databend://0.0.0.0:8000/hello_databend?null_display=null | -| binary_format | binary format, support hex and base64 | hex | jdbc:databend://0.0.0.0:8000/default?binary_format=hex | -| use_verify | whether verify the server before establishing the connection | true | jdbc:databend://0.0.0.0:8000/default?use_verify=true | -| debug | whether enable debug mode | false | jdbc:databend://0.0.0.0:8000/default?debug=true | +| Parameter | Description | Default | example | +|------------------------|---------------------------------------------------------------------------------------------------------------------------|----------|-------------------------------------------------------------------------| +| user | Databend user name | none | jdbc:databend://0.0.0.0:8000/hello_databend?user=test | +| password | Databend user password | none | jdbc:databend://0.0.0.0:8000/hello_databend?password=secret | +| SSL | Enable SSL | false | jdbc:databend://0.0.0.0:8000/hello_databend?SSL=true | +| sslmode | SSL mode | disable | jdbc:databend://0.0.0.0:8000/hello_databend?sslmode=enable | +| copy_purge | If True, the command will purge the files in the stage after they are loaded successfully into the table | false | jdbc:databend://0.0.0.0:8000/hello_databend?copy_purge=true | +| presigned_url_disabled | whether use presigned url to upload data, generally if you use local disk as your storage layer, it should be set as true | false | jdbc:databend://0.0.0.0:8000/hello_databend?presigned_url_disabled=true | +| wait_time_secs | Restful query api blocking time, if the query is not finished, the api will block for wait_time_secs seconds | 10 | jdbc:databend://0.0.0.0:8000/hello_databend?wait_time_secs=10 | +| max_rows_in_buffer | the maximum rows in server session buffer | 5000000 | jdbc:databend://0.0.0.0:8000/hello_databend?max_rows_in_buffer=5000000 | +| max_rows_per_page | the maximum rows per page in response data body | 100000 | jdbc:databend://0.0.0.0:8000/default?max_rows_per_page=100000 | +| connection_timeout | okhttp connection_timeout param | 0 | jdbc:databend://0.0.0.0:8000/default?connection_timeout=100000 | +| query_timeout | time that you wait a SQL execution | 90 | jdbc:databend://0.0.0.0:8000/default?query_timeout=120 | +| null_display | null value display | \N | jdbc:databend://0.0.0.0:8000/hello_databend?null_display=null | +| binary_format | binary format, support hex and base64 | hex | jdbc:databend://0.0.0.0:8000/default?binary_format=hex | +| use_verify | whether verify the server before establishing the connection | true | jdbc:databend://0.0.0.0:8000/default?use_verify=true | +| debug | whether enable debug mode | false | jdbc:databend://0.0.0.0:8000/default?debug=true | +| load_balancing_policy | Specifies the load balancing policy for multi-host connections. Options are "disabled", "random", and "round_robin". | disabled | jdbc:databend://localhost:8000,localhost:8002,localhost:8003/default?load_balancing_policy=random | +| max_failover_retry | Specifies the maximum number of retry attempts for failover connections. | 0 | jdbc:databend://localhost:7222,localhost:7223,localhost:7224,localhost:8000/default?max_failover_retry=4 |