How to Build a Robust Redis Connection Pool Wrapper in Java for Performance Testing
This article walks through creating a reusable Redis connection‑pool manager and a functional wrapper class in Java, explaining pooling concepts, resource recycling, and providing ready‑to‑use methods for common Redis commands to support efficient performance testing with the FunTester framework.
Pooling Technique
Pooling keeps a configurable number of expensive resources (e.g., network connections) alive so that repeated creation overhead is avoided. A pool typically defines minIdle , maxIdle , maxTotal , a blocking queue, health‑check on borrow/return, and optional blocking when the pool is exhausted.
Redis connection‑pool management ( RedisPool )
The RedisPool class creates a JedisPool with the following default configuration (all values are tunable):
MAX_TOTAL = 1000 – maximum number of connections
MAX_IDLE = 300 – maximum idle connections
MIN_IDLE = 10 – minimum idle connections
MAX_WAIT = 5000 ms – maximum time a thread waits for a connection
TIMEOUT = 5000 ms – socket timeout for each connection
testOnBorrow = true – validate a connection before handing it out
testOnReturn = true – validate a connection when it is returned
blockWhenExhausted = true – block instead of throwing when the pool is empty
Typical usage:
JedisPool pool = RedisPool.getPool("127.0.0.1", 6379);Implementation (relevant excerpt):
public class RedisPool {
private static final int MAX_TOTAL = 1000;
private static final int MAX_IDLE = 300;
private static final int MIN_IDLE = 10;
private static final long MAX_WAIT = 5000L;
private static final int TIMEOUT = 5000;
private static final boolean TEST_ON_BORROW = true;
private static final boolean TEST_ON_RETURN = true;
private static final boolean BLOCK_WHEN_EXHAUSTED = true;
private static JedisPoolConfig getConfig() {
JedisPoolConfig cfg = new JedisPoolConfig();
cfg.setMaxTotal(MAX_TOTAL);
cfg.setMaxIdle(MAX_IDLE);
cfg.setMinIdle(MIN_IDLE);
cfg.setMaxWaitMillis(MAX_WAIT);
cfg.setTestOnBorrow(TEST_ON_BORROW);
cfg.setTestOnReturn(TEST_ON_RETURN);
cfg.setBlockWhenExhausted(BLOCK_WHEN_EXHAUSTED);
return cfg;
}
public static JedisPool getPool(String host, int port) {
return new JedisPool(getConfig(), host, port, TIMEOUT);
}
}Resource recycling
After a Jedis instance is used it must be returned to the pool by calling close(). Two common patterns are shown:
// try‑with‑resources (recommended)
public boolean expire(String key, int seconds) {
try (Jedis jedis = getJedis()) {
return jedis.expire(key, seconds) == 1;
} catch (Exception e) {
logger.error("expire key:{} error", key, e);
return false;
}
}
// explicit finally block
public boolean expire(String key, int seconds) {
Jedis jedis = null;
try {
jedis = getJedis();
return jedis.expire(key, seconds) == 1;
} catch (Exception e) {
logger.error("expire key:{} error", key, e);
return false;
} finally {
if (jedis != null) jedis.close();
}
}Functional wrapper class ( RedisBase )
RedisBasebuilds on RedisPool and provides a ready‑to‑use API that wraps common Redis commands with logging and exception handling. The class holds a JedisPool instance, selects a logical database index (default 0), and exposes methods grouped by data type.
Key‑expiration and string operations
public boolean expire(String key, int seconds) { … }
public boolean set(String key, String value, int ttl) { … } // SETEX
public boolean set(String key, String value) { … } // SET
public String get(String key) { … }List operations
public Long lpush(String key, String... values) { … }
public Long rpush(String key, String... values) { … }
public String lpop(String key) { … }
public String rpop(String key) { … }
public List<String> lrange(String key, long start, long end) { … }
public Long llen(String key) { … }
public String lindex(String key, long index) { … }
public String lset(String key, long index, String value) { … }Hash operations
public Long hset(String key, String field, String value) { … }
public String hget(String key, String field) { … }
public Long hdel(String key, String field) { … }
public Boolean hexists(String key, String field) { … }
public Set<String> hkeys(String key) { … }
public List<String> hvals(String key) { … }
public Map<String,String> hgetAll(String key) { … }
public Long hincrBy(String key, String field, long inc) { … }
public Double hincrByFloat(String key, String field, double inc) { … }Set operations
public Long sadd(String key, String... members) { … }
public Long srem(String key, String... members) { … }
public Set<String> smembers(String key) { … }
public String spop(String key) { … }
public List<String> srandmember(String key, int count) { … }
public String srandmember(String key) { … }
public Long scard(String key) { … }Key existence and deletion
public boolean exists(String key) { … }
public Long del(String... keys) { … }
public String type(String key) { … }
public Set<String> getKeys(String pattern) { … }
public Long append(String key, String value) { … }All methods acquire a Jedis instance via getJedis(), which internally calls pool.getResource() and selects the configured database index.
private Jedis getJedis() {
Jedis jedis = pool.getResource();
jedis.select(index);
return jedis;
}Closing the pool
When the application shuts down, invoke close() to release all pooled connections:
public void close() {
pool.close();
}Typical usage pattern
// Initialise wrapper (host and port of Redis server)
RedisBase redis = new RedisBase("127.0.0.1", 6379);
// String set with TTL
redis.set("user:1:name", "Alice", 3600);
// List push and pop
redis.lpush("queue", "task1", "task2");
String next = redis.rpop("queue");
// Hash field increment
redis.hincrBy("stats", "visits", 1);
// Check existence and delete
if (redis.exists("temp:key")) {
redis.del("temp:key");
}
// Release resources when done
redis.close();By combining a well‑tuned JedisPool with the comprehensive RedisBase wrapper, developers can perform functional and performance testing of Redis‑backed services without incurring the overhead of repeatedly establishing connections.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
