executePipelined 能显著降低网络往返开销,但默认不自动启用管道,必须显式调用 RedisConnection.pipelined() 并在回调中使用原生命令操作,漏掉 conn.close() 则命令不会发送。

直接结论:用 executePipelined 能显著降低网络往返开销,但默认行为下它不自动启用管道——必须配合 RedisConnection 手动调用 pipelined() 或确保底层连接工厂支持管道语义;否则你只是在“假装”用管道。
为什么 executePipelined 有时没效果
很多人调用 redisTemplate.executePipelined(...) 后发现耗时和单条命令差不多,根本没提速。原因在于:executePipelined 本身只是一个回调包装器,它是否真正走管道,取决于内部 RedisConnection 是否处于 pipelined 模式。
常见错误场景包括:
- 使用
LettuceConnectionFactory但未显式获取RedisConnection并调用pipelined(),而是直接在SessionCallback里调用opsForValue().set()—— 这些操作仍走普通同步命令 - 在 Redis Cluster 模式下,
getClusterConnection().pipelined()只对同 slot 的 key 有效;跨 slot 会抛RedisClusterException,而executePipelined不做 slot 校验 - 配置了
spring.redis.lettuce.pool,但没配spring.redis.lettuce.shutdown-timeout,导致连接复用异常,管道中途断连
executePipelined 正确写法(Lettuce + 单节点)
必须手动触发管道模式,并在回调中通过 RedisConnection 原生命令操作:
redisTemplate.executePipelined(new SessionCallback<Object>() {
@Override
public <K, V> Object execute(RedisOperations<K, V> operations) throws DataAccessException {
RedisConnection conn = operations.getConnectionFactory().getConnection();
// ⚠️ 关键:显式进入 pipelined 模式
conn = conn.pipelined();
try {
conn.set("k1".getBytes(), "v1".getBytes());
conn.set("k2".getBytes(), "v2".getBytes());
conn.get("k1".getBytes());
conn.get("k2".getBytes());
} finally {
// ⚠️ 必须 close 才真正发送并接收响应
conn.close();
}
return null;
}
});
注意:conn.close() 不是释放连接,而是触发 flush + sync + 返回结果集合;漏掉这步,命令压根没发出去。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
批量操作时的 key 分组与 slot 对齐(Cluster 场景)
Redis Cluster 下管道只支持同 hash slot 的 key。如果你传入的 key 散落在不同 slot,pipelined() 会失败或静默降级为逐条执行。
实操建议:
- 用
RedisClusterConnection.clusterGetNodeForSlot(slot)预判 key 所属节点 - 按
{key}或KEYS[0]方式强制路由(如user:{123}:profile),让相同业务实体的 key 落在同一 slot - 对一批 key 先分组:
Map<redisnode list>> grouped = keys.stream().collect(groupingBy(key -> connection.getClusterConnection().clusterGetNodeForSlot(CRC16.hash(key))));</redisnode> - 每组单独执行
executePipelined,避免跨节点管道失效
性能陷阱:别让序列化拖垮管道收益
管道减少的是网络往返,不是序列化开销。如果 value 是大对象且用 JdkSerializationRedisSerializer,反序列化时间可能远超网络节省时间。
检查点:
- 确认
redisTemplate使用的是StringRedisSerializer或GenericJackson2JsonRedisSerializer,而非默认 JDK 序列化 - 对高频大批量场景,考虑用
MessagePack自定义RedisSerializer,体积比 JSON 小 30%~50% - 管道内不要混用高开销操作:比如在 set 之间插入
evalLua 脚本——Lua 执行是阻塞的,会卡住整条 pipeline
最易被忽略的一点:管道不是万能加速器。当单次请求本身已含大量计算或 DB 查询时,优化 Redis 管道对端到端耗时影响有限——先确认瓶颈真在 Redis 往返,而不是业务逻辑或下游依赖。


















