为什么需要 Redis 连接池?
直接每次操作都创建和销毁 Redis 连接是非常低效的,原因如下:

- 资源消耗大:建立网络连接(TCP 握手)和认证是需要时间和系统资源的,频繁创建和销毁连接会造成巨大的性能开销。
- 延迟高:每次操作都去创建新连接,会增加响应时间,影响用户体验。
- 服务器压力大:Redis 服务器需要处理大量的连接建立和断开请求,会消耗其 CPU 和内存资源,影响其处理核心业务的能力。
连接池的作用就是预先创建一组(可配置数量)的 Redis 连接,并将它们放入一个“池子”中,当需要操作 Redis 时,从池中获取一个连接,用完后归还到池中,而不是直接关闭,这样,连接就可以被复用,避免了上述所有问题。
主流 Java Redis 客户端
在 Java 生态中,有几个主流的 Redis 客户端都支持连接池:
- Lettuce:目前最主流的客户端,它是基于 Netty 的异步和非阻塞连接,性能优秀,支持同步、异步和响应式编程,连接池是其核心功能之一。
- Jedis:老牌、非常流行的客户端,API 设计简单直观,易于上手,它使用阻塞的 I/O 模型,Jedis 2.x 和 3.x 在连接池实现上有很大不同,推荐使用 3.x 及以上版本。
- Redisson:功能非常强大的客户端,除了基础的 Redis 操作,还提供了分布式的数据结构(如 Map, Set, Lock 等),以及很多分布式服务,它也自带了连接池。
本文将以最推荐的 Lettuce 为例进行详细讲解,同时也会提及 Jedis 的配置。
使用 Lettuce 连接池
添加 Maven 依赖
在你的 pom.xml 文件中添加 Lettuce 和 commons-pool2(Lettuce 的连接池实现依赖 commons-pool2)的依赖。

<dependencies>
<!-- Lettuce 核心依赖 -->
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.2.6.RELEASE</version> <!-- 建议使用较新版本 -->
</dependency>
<!-- Lettuce 连接池依赖 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.11.1</version> <!-- 建议使用较新版本 -->
</dependency>
</dependencies>
配置和创建连接池
核心是创建一个 RedisClient,然后使用 GenericObjectPool 来包装它,形成连接池。
以下是完整的配置和示例代码:
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.support.ConnectionPool;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
public class LettucePoolExample {
public static void main(String[] args) {
// 1. 创建 RedisURI,配置连接信息
RedisURI redisURI = RedisURI.Builder
.redis("your.redis.host", 6379) // 替换为你的 Redis 主机和端口
.withPassword("your_password") // 如果有密码,请填写
.withDatabase(0) // 选择数据库
.build();
// 2. 创建 RedisClient 客户端
RedisClient redisClient = RedisClient.create(redisURI);
// 3. 配置连接池
GenericObjectPoolConfig<StatefulRedisConnection<String, String>> poolConfig = new GenericObjectPoolConfig<>();
poolConfig.setMaxTotal(20); // 连接池最大连接数
poolConfig.setMaxIdle(10); // 连接池最大空闲连接数
poolConfig.setMinIdle(5); // 连接池最小空闲连接数
poolConfig.setTestOnBorrow(true); // 在从池中取出对象前,进行有效性验证
poolConfig.setTestOnReturn(false); // 在将对象返回池中前,进行有效性验证
poolConfig.setTestWhileIdle(true); // 在空闲时进行有效性验证
// 其他配置...
// poolConfig.setMaxWaitMillis(3000); // 从池中获取连接的最大等待时间
// 4. 创建连接池
// Lettuce 提供了 ConnectionPool 来包装 GenericObjectPool
ConnectionPool<StatefulRedisConnection<String, String>> connectionPool =
new ConnectionPool<>(poolConfig, redisClient, redisURI);
// 5. 使用连接池
try (StatefulRedisConnection<String, String> connection = connectionPool.borrowObject()) {
// 从连接中获取 Redis 命令接口
String value = connection.sync().get("hello");
System.out.println("从 Redis 获取的值: " + value);
// 也可以执行其他操作
connection.sync().set("key_from_java", "value_from_java");
System.out.println("设置键值对成功");
} catch (Exception e) {
e.printStackTrace();
} finally {
// 6. 归还连接到池中
// 注意:try-with-resources 会在块结束时自动调用 connection.close(),
// 而 ConnectionPool 的 close() 方法就是将连接归还到池中。
// 所以这里可以显式归还,也可以依赖 try-with-resources。
// 如果不使用 try-with-resources,则必须在这里手动归还。
// connectionPool.returnObject(connection);
}
// 7. 应用关闭时,关闭连接池和客户端
try {
connectionPool.close();
redisClient.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
}
关键配置参数解释:
maxTotal: 连接池中最大活跃连接数,根据你的应用并发量来设置,设置过大会导致 Redis 服务器压力过大。maxIdle: 连接池中最大空闲连接数,防止连接池中有过多空闲连接浪费资源。minIdle: 连接池中最小空闲连接数,确保池中始终有连接可用,避免高峰期频繁创建新连接。testOnBorrow: 在获取连接时进行有效性检查(检查连接是否已断开)。true会增加一点开销,但更安全。testWhileIdle: 对空闲连接进行有效性检查,连接池会定期检查空闲连接,确保它们是可用的。
使用 Jedis 连接池
如果你更喜欢使用 Jedis,配置也非常简单。
添加 Maven 依赖
<dependencies>
<!-- Jedis 核心依赖 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.3.1</version> <!-- 建议使用较新版本 -->
</dependency>
</dependencies>
配置和创建连接池
Jedis 提供了 JedisPool 类来直接管理连接池。
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class JedisPoolExample {
public static void main(String[] args) {
// 1. 配置连接池
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(20);
poolConfig.setMaxIdle(10);
poolConfig.setMinIdle(5);
poolConfig.setTestOnBorrow(true);
poolConfig.setTestWhileIdle(true);
// 2. 创建 JedisPool
// JedisPool 的构造函数可以直接传入配置、主机、端口、密码等信息
JedisPool jedisPool = new JedisPool(
poolConfig,
"your.redis.host", // Redis 主机
6379, // Redis 端口
2000, // 连接超时时间 (ms)
"your_password", // 密码
0 // 数据库索引
);
// 3. 使用连接池
try (Jedis jedis = jedisPool.getResource()) {
// 直接使用 Jedis 对象进行操作
String value = jedis.get("hello");
System.out.println("从 Redis 获取的值: " + value);
jedis.set("key_from_java_jedis", "value_from_java_jedis");
System.out.println("设置键值对成功");
} catch (Exception e) {
e.printStackTrace();
} finally {
// 4. 关闭连接池
// 注意:Jedis 的 try-with-resources 会自动调用 jedis.close(),该方法将连接归还给池中。
// 应用关闭时,需要关闭整个池。
jedisPool.close();
}
}
}
最佳实践和注意事项
-
全局唯一:在你的应用中,
RedisClient(Lettuce) 或JedisPool(Jedis) 应该是单例的,不要为每个请求都创建一个新的连接池,通常在应用启动时初始化,在应用关闭时销毁。 -
合理配置参数:
maxTotal,maxIdle,minIdle等参数需要根据你的应用负载和 Redis 服务器性能进行调优,可以通过监控连接池的使用情况(如活跃连接数、等待线程数)来优化配置。 -
异常处理:从连接池中获取连接可能会失败(池已满且设置了超时),需要妥善处理
Exception,如果获取连接失败,可以选择重试或优雅降级。 -
正确释放资源:
- Lettuce: 使用
try-with-resources语句是最安全的方式,能确保StatefulRedisConnection被正确关闭(即归还到池中)。 - Jedis: 同样推荐使用
try-with-resources,jedis.close()会将连接归还给池中。
- Lettuce: 使用
-
考虑使用 Spring Boot:如果你使用的是 Spring Boot,事情会变得非常简单。
spring-boot-starter-data-redis会自动为你配置好Lettuce或Jedis的连接池,你只需要在application.properties或application.yml中配置即可。Spring Boot 示例 (
application.properties):# 使用 Letuce 作为客户端 spring.redis.lettuce.pool.max-active=20 spring.redis.lettuce.pool.max-idle=10 spring.redis.lettuce.pool.min-idle=5 spring.redis.lettuce.pool.max-wait=3000 spring.redis.host=your.redis.host spring.redis.port=6379 spring.redis.password=your_password
Spring Boot 会自动读取这些配置并创建好连接池 Bean,你只需要通过
@Autowired注入RedisTemplate或StringRedisTemplate即可使用。
