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.

FunTester
FunTester
FunTester
How to Build a Robust Redis Connection Pool Wrapper in Java for Performance Testing

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 )

RedisBase

builds 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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaBackend DevelopmentredisPerformance TestingConnection Pool
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.