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.
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.
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);
}
}
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 {
}
}