Skip to content

Commit 2dfd93b

Browse files
authored
Merge pull request #1 from redis-developer/im/aa-support
Add implementation for multidb mode
2 parents ed9bc2b + 05e920a commit 2dfd93b

File tree

11 files changed

+1312
-23
lines changed

11 files changed

+1312
-23
lines changed

application.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ simple.metrics.dumpRate=PT5S
1111
management.otlp.metrics.export.enabled=false
1212
management.otlp.metrics.export.url=http://localhost:4318/v1/metrics
1313
management.otlp.metrics.export.step=PT1S
14+
15+
management.tracing.enabled=false

pom.xml

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<properties>
1818
<java.version>17</java.version>
1919
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
20-
<jedis.version>7.0.0-SNAPSHOT</jedis.version>
20+
<jedis.version>7.0.0</jedis.version>
2121
</properties>
2222

2323
<repositories>
@@ -69,10 +69,6 @@
6969
<groupId>io.micrometer</groupId>
7070
<artifactId>micrometer-core</artifactId>
7171
</dependency>
72-
<dependency>
73-
<groupId>io.micrometer</groupId>
74-
<artifactId>micrometer-registry-influx</artifactId>
75-
</dependency>
7672
<dependency>
7773
<groupId>io.micrometer</groupId>
7874
<artifactId>micrometer-registry-otlp</artifactId>
@@ -111,6 +107,11 @@
111107
<artifactId>jedis</artifactId>
112108
<version>${jedis.version}</version>
113109
</dependency>
110+
<dependency>
111+
<groupId>io.github.resilience4j</groupId>
112+
<artifactId>resilience4j-all</artifactId>
113+
<version>1.7.1</version>
114+
</dependency>
114115
<dependency>
115116
<groupId>io.github.resilience4j</groupId>
116117
<artifactId>resilience4j-circuitbreaker</artifactId>
@@ -126,8 +127,24 @@
126127
<build>
127128
<finalName>jedis-test-app</finalName>
128129

129-
<plugins>
130+
<resources>
131+
<resource>
132+
<directory>src/main/resources</directory>
133+
<filtering>true</filtering>
134+
<includes>
135+
<include>jedis-version.properties</include>
136+
</includes>
137+
</resource>
138+
<resource>
139+
<directory>src/main/resources</directory>
140+
<filtering>false</filtering>
141+
<excludes>
142+
<exclude>jedis-version.properties</exclude>
143+
</excludes>
144+
</resource>
145+
</resources>
130146

147+
<plugins>
131148
<plugin>
132149
<groupId>net.revelc.code.formatter</groupId>
133150
<artifactId>formatter-maven-plugin</artifactId>
@@ -145,7 +162,6 @@
145162
<goal>validate</goal>
146163
</goals>
147164
</execution>
148-
149165
</executions>
150166
</plugin>
151167
<plugin>
@@ -155,10 +171,6 @@
155171
<mainClass>redis.clients.jedis.test.JedisTestApplication</mainClass>
156172
</configuration>
157173
</plugin>
158-
159-
160-
161174
</plugins>
162175
</build>
163-
164176
</project>

runner-config-multidb.yaml

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
runner:
2+
redis:
3+
clientName: "jedis-test-app-multidb"
4+
#username: "default"
5+
#password: "foobared"
6+
verifyPeer: false
7+
8+
test:
9+
mode: multidb # Multi-database mode with failover support
10+
clients: 1 # Number of client instances
11+
connectionsPerClient: 100 # Number of connections per client (used as default pool size)
12+
threadsPerConnection: 1 # Number of threads sharing same connection
13+
workload:
14+
type: redis_commands
15+
maxDuration: PT10S
16+
options:
17+
valueSize: 100 # 100 characters
18+
iterationCount: 10000 # How many iterations to run of the workload before finishing
19+
keyRangeMin: 0 # 0 Minimum key range
20+
keyRangeMax: 1000 # 10000 Maximum key range
21+
22+
clientOptions: # Jedis connection-level options
23+
timeoutOptions:
24+
fixedTimeout: PT2S # Socket/read timeout
25+
socketOptions:
26+
connectTimeout: PT2S # TCP connect timeout
27+
pool:
28+
maxIdle: 100
29+
minIdle: 1
30+
maxWait: PT3S
31+
blockWhenExhausted: true
32+
testWhileIdle: true
33+
timeBetweenEvictionRuns: PT10S
34+
35+
# Multi-database configuration for failover support
36+
# NOTE: For testing with a single Redis instance, we use 127.0.0.1 and localhost
37+
# as different endpoints (they resolve to the same server but are treated as different by Jedis)
38+
# In production, you would use different Redis servers (e.g., different hosts or ports)
39+
# Connection pool settings are taken from clientOptions.pool section (shared across all databases)
40+
multiDbConfig:
41+
databases:
42+
# Primary database (higher weight = higher priority)
43+
- endpoint: redis://localhost:6379/0
44+
weight: 1.0
45+
healthCheckEnabled: true
46+
healthCheckType: ping # Options: ping, lagaware
47+
48+
# Secondary database (lower weight = lower priority, used for failover)
49+
# Using 127.0.0.1 instead of localhost to create a different endpoint identifier
50+
- endpoint: redis://127.0.0.1:6379/0
51+
weight: 0.5
52+
healthCheckEnabled: true
53+
healthCheckType: ping
54+
55+
# Circuit breaker configuration for failure detection
56+
failureDetector:
57+
slidingWindowSize: 1000 # Sliding window size in number of calls
58+
thresholdMinNumberOfFailures: 500 # Minimum number of failures before circuit breaker is tripped
59+
failureRateThreshold: 50.0 # Percentage of failures to trigger circuit breaker
60+
61+
# Retry configuration
62+
commandRetry:
63+
maxAttempts: 3 # Maximum number of retry attempts (including the initial call)
64+
waitDuration: 500 # Number of milliseconds to wait between retry attempts
65+
exponentialBackoffMultiplier: 2 # Exponential backoff factor
66+
67+
# Failback configuration
68+
failbackSupported: true # Enable automatic failback
69+
failbackCheckInterval: 1000 # Check every second for unhealthy database recovery
70+
gracePeriod: 2000 # Keep database disabled for 2 seconds after it becomes unhealthy
71+
72+
# Failover behavior
73+
fastFailover: true # Force closing connections to unhealthy database on failover
74+
retryOnFailover: false # Do not retry failed commands during failover
75+

src/main/java/redis/clients/jedis/test/JedisWorkloadRunner.java

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import org.slf4j.LoggerFactory;
88
import org.springframework.stereotype.Component;
99

10+
import java.io.File;
11+
1012
@Component
1113
public class JedisWorkloadRunner {
1214

@@ -21,6 +23,58 @@ public class JedisWorkloadRunner {
2123
public JedisWorkloadRunner(MetricsReporter metricsReporter, WorkloadRunnerConfig config) {
2224
this.metricsReporter = metricsReporter;
2325
this.config = config;
26+
27+
// Initialize SSL configuration at startup
28+
initializeSslConfiguration();
29+
}
30+
31+
/**
32+
* Initialize SSL/TLS configuration for the application.
33+
*
34+
* This method configures JVM-wide SSL truststore properties based on the runner configuration. The truststore is used for
35+
* all SSL/TLS connections made by the application, including: - Redis connections over SSL/TLS - LagAware health check REST
36+
* API calls - Any other HTTPS connections
37+
*/
38+
private void initializeSslConfiguration() {
39+
WorkloadRunnerConfig.SslConfig sslConfig = config.getSsl();
40+
41+
if (sslConfig == null || sslConfig.getTruststorePath() == null) {
42+
log.debug("No SSL truststore configuration provided, using JVM defaults");
43+
return;
44+
}
45+
46+
String truststorePath = sslConfig.getTruststorePath();
47+
String truststorePassword = sslConfig.getTruststorePassword();
48+
String truststoreType = sslConfig.getTruststoreType() != null ? sslConfig.getTruststoreType() : "JKS";
49+
50+
File truststoreFile = new File(truststorePath);
51+
if (!truststoreFile.exists()) {
52+
log.warn("SSL truststore file not found at: {}", truststoreFile.getAbsolutePath());
53+
log.warn("SSL connections may fail if server certificates cannot be verified");
54+
return;
55+
}
56+
57+
if (!truststoreFile.canRead()) {
58+
log.warn("SSL truststore file is not readable at: {}", truststoreFile.getAbsolutePath());
59+
log.warn("SSL connections may fail if server certificates cannot be verified");
60+
return;
61+
}
62+
63+
log.info("Configuring JVM-wide SSL truststore");
64+
log.info(" Truststore path: {}", truststoreFile.getAbsolutePath());
65+
log.info(" Truststore type: {}", truststoreType);
66+
67+
// Set JVM-wide SSL truststore properties
68+
// These properties are used by:
69+
// - HttpsURLConnection (used by LagAware REST API calls)
70+
// - SSLContext.getDefault() (used by various SSL/TLS clients)
71+
System.setProperty("javax.net.ssl.trustStore", truststoreFile.getAbsolutePath());
72+
if (truststorePassword != null) {
73+
System.setProperty("javax.net.ssl.trustStorePassword", truststorePassword);
74+
}
75+
System.setProperty("javax.net.ssl.trustStoreType", truststoreType);
76+
77+
log.info("JVM-wide SSL truststore configured successfully");
2478
}
2579

2680
public void run() {
@@ -29,8 +83,12 @@ public void run() {
2983
runner = new StandaloneJedisWorkloadRunner(config, metricsReporter);
3084
log.info("Running standalone workload (Jedis/UnifiedJedis)");
3185
}
32-
default -> throw new IllegalArgumentException("Unsupported mode for Jedis app: " + config.getTest().getMode()
33-
+ ". Only STANDALONE is supported for Jedis right now.");
86+
case "MULTIDB" -> {
87+
runner = new MultiDbJedisWorkloadRunner(config, metricsReporter);
88+
log.info("Running multi-database workload with failover support (MultiDbClient)");
89+
}
90+
default -> throw new IllegalArgumentException(
91+
"Unsupported mode for Jedis app: " + config.getTest().getMode() + ". Supported modes: STANDALONE, MULTIDB");
3492
}
3593
runner.run();
3694
}

0 commit comments

Comments
 (0)