先给我吐槽一下,简直就是玩我个 der,不过打铁还得自身硬,自己还是太菜了,玩个毛球哦。
故事
今天突然发现,哎,服务缓存失效了,具体原因就是因为 redis 数据库设置密码时候设置了个 @ 符号,好家伙,就是因为这个东西,加上 jetcache 采用 lettuce 进行连接,而在 lettuce 连接时采用解析 uri 的形式,但是 uri 解析时候 @ 会当作分割符号进行处理,这样就导致 redis 连接不上,之后看了源码后进行更改,更改后又给我报了一个 redis 不支持集群,哦豁,最后没得办法改用 redis 的 jedis 连接方式,果断放弃了 lettuce,问题得以解决。
问题一: lettuce 解析 uri 中的 @ 分割符
描述
在配置 jetcache 文件时候,由于 redis 数据库密码存在 @,由于是线上环境,不能更改,然后 jetcache 采用 lettuce 连接,解析 uri 时出错,导致连接失败,缓存失效。具体配置如下:
jetcache:
statIntervalMinutes: 1 #统计间隔
areaInCacheName: false
local:
default: #默认area
type: caffeine
keyConvertor: fastjson
limit: 10000 #本地缓存最大个数
defaultExpireInMillis: 10000 #缓存的时间全局 默认值
remote:
default:
type: redis.lettuce #使用lettuce
keyConvertor: fastjson
valueEncoder: java
valueDecoder: java
poolConfig:
minIdle: 1
maxIdle: 50
maxTotal: 1000
maxWait: 1000
uri: redis://xxx@xxx@ip:6379/0 #redis://密码@IP:端口/库
分析源码
先看源码(只拿出来关键的看):
解析 uri 源码:
解决方式
既然是因为解析 URI 出现的问题,那么我们是不是重新实现一下就好了,于是我的解决方式是写一个 redisConfig 配置文件,通过直接调用 RedisClusterClient.create()来解决问题。
关键代码如下:
@Bean
public RedisClusterClient redisClient(){
ArrayList<RedisURI> list = new ArrayList<>();
RedisURI redisURI = new RedisURI();
redisURI.setHost(host);
redisURI.setPassword(password);
redisURI.setPort(Integer.parseInt(port));
redisURI.setDatabase(Integer.parseInt(database));
list.add(redisURI);
return RedisClusterClient.create(list);
}
或者:
@Bean
public RedisClusterClient redisClient(){
ArrayList<RedisURI> list = new ArrayList<>();
RedisURI redisURI = new RedisURI();
redisURI.setHost("127.0.0.1");
redisURI.setPassword("XXXX@XXXX");
redisURI.setPort(1234);
list.add(redisURI);
RedisClusterClient client = RedisClusterClient.create(list);
client.setOptions(ClusterClientOptions.builder().
disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS)
.build());
return client;
}
完整实现:
@Configuration
public class JetCacheConfig{
@Value(value = "${spring.redis.host}")
private String host;
@Value(value = "${spring.redis.port}")
private String port;
@Value(value = "${spring.redis.database}")
private String database;
@Value(value = "${spring.redis.password}")
private String password;
@Bean
public RedisClusterClient redisClient(){
ArrayList<RedisURI> list = new ArrayList<>();
RedisURI redisURI = new RedisURI();
redisURI.setHost(host);
redisURI.setPassword(password);
redisURI.setPort(Integer.parseInt(port));
redisURI.setDatabase(Integer.parseInt(database));
list.add(redisURI);
return RedisClusterClient.create(list);
}
@Bean
public SpringConfigProvider springConfigProvider() {
return new SpringConfigProvider();
}
@Bean
public GlobalCacheConfig config(SpringConfigProvider configProvider, RedisClusterClient redisClient){
Map localBuilders = new HashMap();
EmbeddedCacheBuilder localBuilder = LinkedHashMapCacheBuilder
.createLinkedHashMapCacheBuilder()
.keyConvertor(FastjsonKeyConvertor.INSTANCE);
localBuilders.put(CacheConsts.DEFAULT_AREA, localBuilder);
Map remoteBuilders = new HashMap();
RedisLettuceCacheBuilder remoteCacheBuilder = RedisLettuceCacheBuilder.createRedisLettuceCacheBuilder()
.keyConvertor(FastjsonKeyConvertor.INSTANCE)
.valueEncoder(JavaValueEncoder.INSTANCE)
.valueDecoder(JavaValueDecoder.INSTANCE)
.redisClient(redisClient);
remoteBuilders.put(CacheConsts.DEFAULT_AREA, remoteCacheBuilder);
GlobalCacheConfig globalCacheConfig = new GlobalCacheConfig();
//globalCacheConfig.setConfigProvider(configProvider);//for jetcache <=2.5
globalCacheConfig.setLocalCacheBuilders(localBuilders);
globalCacheConfig.setRemoteCacheBuilders(remoteBuilders);
globalCacheConfig.setStatIntervalMinutes(15);
globalCacheConfig.setAreaInCacheName(false);
return globalCacheConfig;
}
}
就在这个时候我以为万事俱备只欠东风的时候,我一启动,哦豁,凉凉。
问题二、采用 lettuce 出现集群禁用问题
问题
redis 设计时候只想到了单机,并没考虑集群,导致 lettuce 进行 RedisClusterClient 连接时候出现 redis 不支持集群操作
io.lettuce.core.RedisCommandExecutionException: ERR This instance has cluster support disabled
at io.lettuce.core.ExceptionFactory.createExecutionException(ExceptionFactory.java:135) ~[lettuce-core-5.1.7.RELEASE.jar:na]
看到网上的解决办法是修改 redis 配置文件,可是这是线上环境,不敢乱动,所以果断放弃,修改方式如下(未实验是否可行):
修改 redis 配置文件 redis.conf
去掉前面的#号
# cluster-enabled yes
解决方式
果断放弃 lettuce,采用 jedis 进行连接
jetcache:
statIntervalMinutes: 15 #统计间隔
areaInCacheName: false
local:
default: #默认area
type: caffeine
keyConvertor: fastjson
limit: 1000 #本地缓存最大个数
defaultExpireInMillis: 100000 #缓存的时间全局 默认值
remote:
default:
type: redis
keyConvertor: fastjson
valueEncoder: java
valueDecoder: java
poolConfig:
minIdle: 1
maxIdle: 50
maxTotal: 1000
maxWait: 1000
host: ${spring.redis.host}
port: ${spring.redis.port}
database: ${spring.redis.database}
password: ${spring.redis.password}
区别在原来是 remote.default.type 是 redis.lettuce 现在直接用 redis
ps: 可能会出现
Caused by: java.lang.NoClassDefFoundError: redis/clients/util/Pool
这是由于 jedis 不存在或者是版本不匹配,自己引入就可以
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.0.0</version>
</dependency>
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于