Redis 连接问题完整解决报告

Redis 连接问题完整解决报告

一、问题现象

Spring Boot 3.4.0 应用启动后,调用 /api/agent/chat 接口时报错:

org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis

Caused by: io.lettuce.core.RedisConnectionException: Unable to connect to xxxxxxx/<unresolved>:6379

Caused by: io.lettuce.core.RedisCommandExecutionException: NOAUTH Authentication required

二、排查过程

  1. 初步排查 - 密码配置问题
  • 检查 application.yaml 发现密码包含特殊字符 +

  • 尝试用引号包裹密码:password: "xx"

  • 结果:无效,问题依旧

  1. 手动配置 RedisConnectionFactory
  • 创建 RedisConfig.java 手动配置 LettuceConnectionFactory

  • 硬编码密码测试

  • 结果:无效,问题依旧

  1. DNS 解析排查
  • 错误日志显示 <unresolved> 表示 DNS 未解析

  • 使用 nslookup 命令验证 DNS 正常解析到 xx

  • 尝试直接使用 IP 地址连接

  • 尝试配置 Lettuce 使用 JDK DNS Resolver

  • 结果:无效,问题依旧

  1. Socket 直连测试
  • 编写 Java Socket 代码直接连接 Redis 发送 AUTH/PING 命令

  • 结果:

Socket连接成功

AUTH响应: +OK

PING响应: +PONG

  • 结论:密码正确、网络正常、DNS 正常
  1. 替换为 Jedis
  • 排除 Lettuce,改用 Jedis

  • 结果:✅ 连接成功

  1. 对比分析正常项目
  • 查看 项目B(能正常使用 Lettuce)

  • 发现关键配置差异:

ClientOptions clientOptions = ClientOptions.builder()

.protocolVersion(ProtocolVersion.RESP2)

.build();

  1. Redis 版本确认
  • Socket 发送 INFO server 命令获取版本

  • 结果:redis_version:5.0

  1. 最终定位
  • Lettuce 6.x 默认使用 RESP3 协议

  • Redis 5.0 仅支持 RESP2 协议

  • 协议版本不匹配导致认证失败

三、根本原因

┌──────────────────┬──────────┬────────────────┐

│ 组件 │ 默认协议 │ 问题 │

├──────────────────┼──────────┼────────────────┤

│ Lettuce 6.x │ RESP3 │ 默认使用 RESP3 │

├──────────────────┼──────────┼────────────────┤

│ 阿里云 Redis 5.0 │ RESP2 │ 不支持 RESP3 │

└──────────────────┴──────────┴────────────────┘

RESP3 协议在 Redis 6.0+ 才引入,Redis 5.0 只支持 RESP2。Lettuce 用 RESP3 连接 Redis 5.0 时,协议握手失败,导致后续 AUTH 命令格式不正确。

四、解决方案

方案一:强制使用 RESP2 协议(推荐)

@Configuration

public class RedisConfig {

@Value("${spring.data.redis.host}")

private String host;

@Value("${spring.data.redis.port}")

private int port;

@Value("${spring.data.redis.password}")

private String password;

@Value("${spring.data.redis.database}")

private int database;

@Bean

@Primary

public LettuceConnectionFactory redisConnectionFactory() {

RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();

config.setHostName(host);

config.setPort(port);

config.setPassword(RedisPassword.of(password));

config.setDatabase(database);

// 关键配置:强制使用 RESP2 协议

ClientOptions clientOptions = ClientOptions.builder()

.protocolVersion(ProtocolVersion.RESP2)

.build();

LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()

.clientOptions(clientOptions)

.build();

LettuceConnectionFactory factory = new LettuceConnectionFactory(config, clientConfig);

factory.setShareNativeConnection(false);

factory.afterPropertiesSet();

return factory;

}

@Bean

public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {

RedisTemplate<String, Object> template = new RedisTemplate<>();

template.setConnectionFactory(connectionFactory);

template.setKeySerializer(new StringRedisSerializer());

template.setValueSerializer(new StringRedisSerializer());

return template;

}

@Bean

public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory connectionFactory) {

return new StringRedisTemplate(connectionFactory);

}

}

五、RESP 协议版本对照表

┌─────────────────┬──────────────┬──────────────────┐

│ Redis 版本 │ 支持协议 │ 说明 │

├─────────────────┼──────────────┼──────────────────┤

│ Redis 2.x - 5.x │ RESP2 │ 仅支持 RESP2 │

├─────────────────┼──────────────┼──────────────────┤

│ Redis 6.0+ │ RESP2, RESP3 │ 同时支持两种协议 │

└─────────────────┴──────────────┴──────────────────┘

┌──────────────┬──────────┬────────────────────────────┐

│ Lettuce 版本 │ 默认协议 │ 说明 │

├──────────────┼──────────┼────────────────────────────┤

│ Lettuce 5.x │ RESP2 │ 默认 RESP2 │

├──────────────┼──────────┼────────────────────────────┤

│ Lettuce 6.x │ RESP3 │ 默认 RESP3,可配置为 RESP2 │

└──────────────┴──────────┴────────────────────────────┘

六、验证 Redis 版本的方法

方法1:redis-cli

redis-cli -h <host> -p <port> -a <password> INFO server

方法2:Java Socket

Socket socket = new Socket(host, port);

PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

out.println("AUTH " + password);

in.readLine();

out.println("INFO server");

// 解析输出中的 redis_version 行

七、关键经验总结

  1. 错误信息 <unresolved> 不一定是 DNS 问题 - 可能是协议层错误导致的副作用

  2. Socket 测试能排除网络、密码、DNS 问题 - 简单有效的诊断手段

  3. 对比正常项目配置 - 快速发现关键差异

  4. Lettuce 6.x + Redis 5.x 组合需要强制 RESP2 - 重要兼容性问题

相关推荐
OceanBase数据库官方博客8 小时前
被 VLDB 2027接收OceanBase 最新论文让数据库基(技术解析与实践)
数据库·人工智能·oceanbase
创邻科技9 小时前
国产图数据库刷新 LDBC 世界纪录:创邻科技 Galaxybase 在 SF100、SF300、SF1000 测试中全面领先”
数据库·科技
GreatSQL社区9 小时前
主从复制SQL线程中断——字符集砸出的坑
java·数据库·算法
XLYcmy9 小时前
AI 赋能后中文与英文数据库对比分析报告 上
数据库·ai·llm·prompt·检索·wos·cnki
这个DBA有点耶10 小时前
ELT 工具选型完整指南:从 ETL 差异分析到工程落地
数据库·架构·代码规范
IvorySQL10 小时前
PostgreSQL 日报|堆表选择性索引更新(10 月 13 日)
数据库·人工智能·postgresql·开源·区块链
张洛闻Eren10 小时前
Ansible【第一课】:Ansible介绍
运维·数据库·云原生·kubernetes·github·ansible
深圳市益普科技有限公司10 小时前
中小封装厂上 MES,为什么十个项目九个坑?
大数据·数据库·人工智能
云边云科技_云网融合10 小时前
从 POS 机到访客 Wi-Fi:零售门店安全建设的完整解法
服务器·网络·数据库
天行健,君子而铎11 小时前
知形-数据库风险监测系统:非侵入式、可溯源、差异化的数据库安全方案
网络·数据库·安全