跳至主要內容

Redis 常见问题

码匠君SASSpring Authorization ServerDante Cloud微服务领域驱动DDDSpring BootSpring CloudSpring SecuritySpring Cloud AlibabaSpring Cloud TencentOAuth2.1NacosSkywalkingSentinelSeata大约 5 分钟

Redis 常见问题

[1]服务启动后,无法连接 Redis 抛错

背景

Dante Cloud 基础服务在启动时必须要连接 Redis,连接成功后才能正常运行。

目前涉及到 Redis 的内容,主要包括两部分:

  1. 常规的数据缓存特别像 Session、验证码一类的临时缓存,这一类缓存根据场景以及实现要求的不同,有些会直接使用 Redis;
  2. 数据共享缓存,像权限数据、CRUD 数据等缓存,这一类缓存除了要实现数据缓存的目的之外,还要解决缓存数据在多服务、多实例环境下数据共享同步等问题。因此采用的是 JetCache 多级缓存组件。

因本项目更倾向于贴近 Spring 生态,尽量使用 Spring 生态主打或推荐的相关组件。所以不管是直接访问 Redis 还是集成 JetCache,底层数据访问客户端组件均使用的是 lettuce。也正因为如此,Spring 生态相关组件自身的不足也会体现在 Dante Cloud 中。

问题原因

服务启动后无法连接 Redis,除了网络问题导致的无法连接以外,最主要的诱因就是:Redis 密码中包含特殊字符

包含特殊字符的密码导致 Redis 无法连接,原因大概出自两方面:

  • 一方面是 Spring Boot 基本规范导致。Spring Boot Yaml 对特殊字符是有处理要求的,Yaml 配置信息中,如果包含以下特殊字符必须要进行转义
:, {, }, [, ], ,, &, *, #, ?, |, -, <, >, =, !, %, @, `
  • 另一方面是基础组件自身处理机制导致。有些组件是采用 uri 的方式进行 Redis 连接配置,而有些组件使用 ip + 端口等方式处理。所以就可能存在,同样的密码,使用 Jedis、Redisson 等组件是正常的,换到 Dante Cloud 所使用的 lettuce 就不正常;甚至可能使用 lettuce 是正常的,换到 JetCache 又会有问题。

解决方法

方法一

这个方法最直接最简单,就是修改 Redis 密码,去掉密码中的某个或者全部特殊字符。

提示

很多人都期望通过增加 Redis 密码复杂度来提升 Redis 的安全性。不可否认这确实能提升一定的安全性,但是毕竟 Redis 的密码安全机制太过简单,所以个人建议不要太过于依赖于此,网络层面或者物理层面保证 Redis 的相对隔离才能靠谱。(换句话说 Redis 密码复杂度更像是心理安慰,不能从本质上提升多大的安全性,所以就不要太纠结密码中要不要包含特殊字符的问题)

方法二

对密码中的特殊字符进行转义,以保证可以正确被读取和使用。

  • 在 Spring Boot Yaml 方面,如果存在特殊字符就需要对密码字符串进行转义,例如下例中密码包含了特殊字符 “#”,这种写法是会出现运行错误问题的
spring:
  #data source connection
  datasource:
    url: jdbc:mysql://localhost:3306/vaquarkhan
    username: rootadmin
    password: root#

需要对特殊字符进行转义:

可以用引号包裹字符串进行转义

"root#"

或者用反斜杠

root\#

完整的例子

spring:
  #data source connection
  datasource:
    url: jdbc:mysql://localhost:3306/vaquarkhan
    username: rootadmin
    password: "root#"
  • 对于像 JetCache 一样使用 uri 进行 Redis 连接配置的,那么特殊字符的转义,就要参考 url.encode 的方式,例如:
符号-转义结果符号-转义结果
空格-%20/-%2F
"-%22:-%3A
#-%23;-%3B
%-%25<-%3C
&-%26=-%3D
(-%28>-%3E
)-%29?-%3F
+-%2B@-%40
,-%2C\-%5C

一个完成的参考示例,需要转义,spring Data redis 使用'',而 jetcache 使用 URL 转义

spring:
  application:
    redis:
      password: "123@!"
jetcache:
  remote:
    test:
      uri: redis://123%40%21@${spring.redis.host}:${spring.redis.port}/${spring.redis.database}
      poolConfig:
        minIdle: 5
        maxIdle: 20
        maxTotal: 50

[2]本地 Redis 使用 127.0.0.1 可以访问,使用 IP 地址无法访问

Redis 默认只允许通过 127.0.0.1 访问,这是其自身的安全防护机制。如果想要使用 IP 地址进行访问,需要将其保护设置打开。

  • Windows 版

找到redis.windows.conf配置文件

  1. protected-mode 参数改为 no。

  2. 注释掉bind 127.0.0.1

  3. 重启 redis 服务

Redis 密码
Redis 密码
  • Linux
  1. linux 对应的是redis.conf文件

  2. 修改还是和 windows 一样

  3. 修改完成重启服务

[3]io.lettuce.core.RedisCommandExecutionException: NOAUTH Authentication required

出现该错误,是由于 Redis 中设置密码,而代码中未读到 Redis 密码或配置文件中没有配置密码导致的。

  • 解决办法
  1. 首先用Redis客户端,比如:redis-desktop-manager,进行Redis的连接测试。如果无法连接,那么请检查密码输入是否正确,本地网络等相关环境;如果可以正常连接,请进行下一步。
  2. 检查Nacos中,Redis相关配置是否配置了密码。一定要注意格式,检查格式缩进是否正确,yaml配置“:”后面是否空了一格。如果确定配置正确,请进行下一步。
  3. 检查服务是否可以正常访问到Nacos服务器,是否可以正确读取Nacos中配置。

以上操作均确保无误应该就可以正常使用了,如果还有问题,那么就请尽可能的准备详尽的信息,在 Gitee 中提Issueopen in new window

[4]NOAUTH HELLO must be called with the client already authenticated, otherwise the HELLO AUTH < user >

使用spring boot data redis 链接redis sentinel集群,会报此错。

原因是因为redis sentinel集群的sentinel配置文件没有配置密码,sentinel配置密码的方式和 redis 的密码配置方式一样,配置文件中加上requirepass <密码> 就行。

另外,sentinel中的sentinel auth-pass <master> <pass> 不是给sentinel配置密码,而是sentinel链接redis master的密码