高并发场景下spring boot项目优先选lettuce,因其基于netty的响应式连接模型支持连接复用和真正异步操作,而jedis阻塞式连接易因线程数激增导致连接池争抢、i/o等待和泄漏。

高并发场景下,Spring Boot 项目优先选 Lettuce,不是因为它“更先进”,而是它基于 Netty 的响应式连接模型天然适合连接复用和异步操作,而 Jedis 的阻塞式 TCP 连接在连接数激增时容易成为瓶颈。
为什么 Jedis 在高并发下容易扛不住
Jedis 是同步阻塞客户端,每个线程默认独占一个 Jedis 实例(或从 JedisPool 获取连接),连接数 = 并发线程数 × 每线程连接数。当 QPS 上千、微服务实例多、且开启 pipeline 或事务时:
- 连接池频繁争抢,
JedisPool.getResource()出现明显等待,日志里常看到Could not get a resource from the pool - Redis 响应稍慢(比如 10ms),线程就卡住 10ms,CPU 大量空转等 I/O
- 连接泄漏风险高:忘记
close()或异常路径未回收,池子迅速耗尽 -
Jedis不支持真正的命令异步化,Future是包装层模拟,底层仍是同步调用
Lettuce 的连接模型怎么缓解这个问题
Lettuce 默认共享一个 StatefulRedisConnection(或连接池中的多个),底层由 Netty EventLoop 管理 I/O,所有命令都走异步 pipeline,真正实现“一个连接处理大量并发请求”:
- Spring Boot 2.0+ 默认集成
Lettuce,RedisTemplate底层自动使用LetutceConnectionFactory - 连接数可控:通常单实例配 1–4 个
StatefulRedisConnection就够,不随线程数线性增长 - 支持真正的异步:
connection.async().set("k","v")返回RedisFuture,可组合、可超时控制 - 自动重连:网络闪断后,
Lettuce能静默重建连接,Jedis需手动 catchJedisConnectionException并重试 - 注意:若显式配置了
GenericObjectPoolConfig给LettuceClientConfigurationBuilder,反而会退化为连接池模式,失去复用优势——除非你明确需要隔离(如多租户)
切换到 Lettuce 后要注意的坑
不是把依赖一换就万事大吉,几个关键点不调,照样翻车:
- 确认没残留
Jedis依赖:检查mvn dependency:tree,排除spring-boot-starter-data-redis间接引入的jedis,否则 Spring 会 fallback 到Jedis -
Lettuce默认不开启 SSL 和认证时,连接超时是 60 秒;生产必须设clientOptions( ClientOptions.builder().socketOptions(SocketOptions.builder().connectTimeout(Duration.ofSeconds(3)).build()).build()) - 事务行为不同:
Lettuce的multi()+exec()是纯客户端状态管理,失败不会自动 rollback;而Jedis的multi()抛异常后连接会进 dirty 状态,需主动 reset - 集群模式下,
Lettuce对MOVED/ASK重定向是自动的,但遇到跨槽KEYS或SCAN仍会报错——这不是客户端问题,是 Redis Cluster 限制本身
真正决定性能上限的,从来不是客户端名字,而是连接生命周期管理是否与业务吞吐节奏匹配。Lettuce 的优势只在连接被充分复用时才体现;如果每个 HTTP 请求都 new 一个 RedisClient 再 close,那它和 Jedis 没区别。










