Proper values of JedisPool parameters allow you to improve the performance of Redis. This topic describes how to use JedisPool and configure the resource pool parameters. This topic also describes recommended parameter configurations to optimize JedisPool.

How to use JedisPool

Jedis 2.9.0 is used in this example. The following sample code shows the Maven dependency:

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
    <scope>compile</scope>
</dependency>

Jedis manages the resource pool by using Apache Commons-pool2. When you define JedisPool, we recommend that you consider the GenericObjectPoolConfig parameter (resource pool). The following sample code shows how to use this parameter.

GenericObjectPoolConfig jedisPoolConfig = new GenericObjectPoolConfig();
jedisPoolConfig.setMaxTotal(...);
jedisPoolConfig.setMaxIdle(...);
jedisPoolConfig.setMinIdle(...);
jedisPoolConfig.setMaxWaitMillis(...) ;
...

The following example shows how to initialize JedisPool:

// redisHost specifies the IP address of the instance. redisPort specifies the port of the instance. redisPassword specifies the password of the instance. The timeout parameter specifies both the connection timeout and the read/write timeout.
JedisPool jedisPool = new JedisPool(jedisPoolConfig, redisHost, redisPort, timeout, redisPasswor//d);
// Run the following command:
Jedis jedis = null;
try {
    jedis = jedisPool.getResource();
    // Specific commands
    jedis.executeCommand()
} catch (Exception e) {
    logger.error(e.getMessage(), e);
} finally {
    // In JedisPool mode, the Jedis resource is returned to the resource pool.
    if (jedis ! = null) 
        jedis.close();
}

Parameters

The Jedis connection is a resource managed by JedisPool in the connection pool. JedisPool is a thread-safe pool of connections. It allows you to keep all resources within a manageable range. Specify the GenericObjectPoolConfig parameter properly can improve the performance of Redis and reduce the resource consumption. The following two tables list some important parameters and provide recommended configurations.

Table 1. Parameters related to resource settings and resource usage
Parameter Description Default value Recommendation
maxTotal The maximum number of connections that are supported by the pool. 8 For more information, see Recommendations for key parameters.
maxIdle The maximum number of idle connections in the pool. 8 For more information, see Recommendations for key parameters.
minIdle The minimum number of idle connections in the pool. 0 For more information, see Recommendations for key parameters.
blockWhenExhausted Specifies whether the client must wait when the resource pool is exhausted. The following maxWaitMillis parameter takes effect only when this parameter is set to true. true We recommend that you use the default value.
maxWaitMillis The maximum number of milliseconds that the client needs to wait when no connection is available. A value of -1 specifies that the connection will never time out. We recommend that you do not use the default value.
testOnBorrow Specifies whether connections will be validated by using the PING command before they are borrowed from the pool. Invalid connections will be removed from the pool. false We recommend that you set this parameter to false when the workload is heavy. This allows you to reduce the consumption caused by a ping test.
testOnReturn Specifies whether connections will be validated using the PING command before they are returned to the pool. Invalid connections will be removed from the pool. false We recommend that you set this parameter to false when the workload is heavy. This allows you to reduce the consumption caused by a ping test.
jmxEnabled Specifies whether to enable JMX monitoring. true We recommend that you enable JMX monitoring. Note that the feature of your application also needs to be enabled.

Idle Jedis object detection consists of the following four parameters. testWhileIdle is the switch of this feature.

Table 2. Parameters related to idle resource detection
Parameter Description Default value Recommendation
testWhileIdle Specifies whether to enable the idle resource detection. false true
timeBetweenEvictionRunsMillis Specifies the cycle of idle resources detection. Unit: milliseconds. A value of -1 specifies that no idle resource are detected. We recommend that you specify this parameter and set it to a proper value as needed. You can also use the default configuration in JedisPoolConfig.
minEvictableIdleTimeMillis The minimum idle time in milliseconds of a resource in the resource pool. When the upper limit is reached, the idle resource will be evicted. 180000 (30 minutes) The default value is suitable for most cases. You can also use the configuration in JeidsPoolConfig based on your business requirements.
numTestsPerEvictionRun The number of resources to be detected at each idle resource detection. 3 You can change the value based on your application connections. A value of -1 specifies that idle resource detection will be performed on all connections.

Jedis provides JedisPoolConfig that uses some configurations of GenericObjectPoolConfig for idle resource detection.

public class JedisPoolConfig extends GenericObjectPoolConfig {
  public JedisPoolConfig() {
    // defaults to make your life with connection pool easier :)
    setTestWhileIdle(true);
    //
    setMinEvictableIdleTimeMillis(60000);
    //
    setTimeBetweenEvictionRunsMillis(30000);
    setNumTestsPerEvictionRun(-1);
    }
}
Note You can view all default values in org.apache.commons.pool2.impl.BaseObjectPoolConfig.

Recommendations for key parameters

maxTotal: The maximum number of connections.

To set a proper value of maxTotal, you need to take into account the following factors:

  • The required concurrent connections based on business requirements.
  • The amount of time that is consumed by the client to run the command.
  • The limit of Redis resources. For example, the product of multiplying maxTotal by the number of nodes (applications) must be smaller than the supported maximum number of connections in Redis. You can view the maximum connections on the Instance Information page in the ApsaraDB for Redis console.
  • The resource that is cost to create and release connections. When the number of connections created and released is large for each request, the creation and release process takes a heavy toll.

The time for running a command to obtain a resource consists of the time to borrow or return the resource, the time consumed for JedisPool to run the command, and the time for network connection. For example, the average time consumed to run a command to obtain a resource is about 1 ms, the queries per second (QPS) of a connection is about 1,000, and the expected QPS is 50,000. In this case, the required theoretical pool size is 50 (50,000/1,000 = 50).

But this is only a theoretical value. To reserve some resources, the value of the maxTotal parameter can be larger than the theoretical value. However, if this value is too large, the connections will consume a large amount of client and server resources. On the other hand, for servers like Redis that has a high QPS, if a large number of commands block, even a large resource pool cannot solve this problem.

maxIdle and minIdle

maxIdle is the actual maximum number of connections required by the business. maxTotal includes the number of idle connections as a surplus. If the value of maxIdle is too small on heavily loaded systems, new Jedis (extra connections) will be created to serve the requests. Therefore, minIdle specifies the minimum number of established connections that need to be kept in the pool.

The connection pool reaches its best performance when maxTotal = maxIdle. This way, the performance is not affected by the scaling of the connection pool. We recommend that you set the values of both parameters to the same value during peak hours of your services. However, if the number of concurrent connections is small or the value of the maxIdle parameter is too large, the connection resources will be wasted.

You can evaluate the size of the connection pool used by each node based on the actual total QPS and the number of clients that call Redis.

Retrieve proper values based on monitoring data

In actual scenarios, a more reliable method is to try to retrieve optimal values based on monitoring data. You can use JMX monitoring or other monitoring tools to discover proper values.

FAQ

Insufficient resources

In the following cases, you cannot obtain resources from the resource pool.

  • Timeout:
    redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
    ...
    Caused by: java.util.NoSuchElementException: Timeout waiting for idle object
    at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:449)
  • When you set the blockWhenExhausted parameter to false, the time specified by borrowMaxWaitMillis is not used and the borrowObject call will block until an idle connection is available.

    redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
    ...
    Caused by: java.util.NoSuchElementException: Pool exhausted
    at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:464)

This exception may not be caused by limited pool size. For more information, see Recommendations for key parameters. To fix this issue, we recommend that you check the network, parameters of the resource pool, the resource pool monitoring (JMX monitoring), the code (for example, the reason may be that jedis.close() is not executed), slow queries, and DNS.

Preload JedisPool

The project may quickly time out after it is started if you specify a small timeout value. JedisPool does not create a Jedis connection in the connection pool when it defines the maximum number of resources and the minimum number of idle resources. If no idle connection exists in the pool, a new Jedis connection is created. This connection will be released to the pool after it is used. However, it may take a long period of time to create a new connection and release it every time. Therefore, we recommend that you preload JedisPool with the minimum number of idle connections after JedisPool is defined. The following example shows how to repload JedisPool:

List<Jedis> minIdleJedisList = new ArrayList<Jedis>(jedisPoolConfig.getMinIdle());

for (int i = 0; i < jedisPoolConfig.getMinIdle(); i++) {
    Jedis jedis = null;
    try {
        jedis = pool.getResource();
        minIdleJedisList.add(jedis);
        jedis.ping();
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
    } finally {
    }
}

for (int i = 0; i < jedisPoolConfig.getMinIdle(); i++) {
    Jedis jedis = null;
    try {
        jedis = minIdleJedisList.get(i);
        jedis.close();
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
    } finally {
    
    }
}