zl程序教程

您现在的位置是:首页 >  数据库

当前栏目

停止redis集群后清除数据重启,Redisson无法自动重连问题解决方法

Redis方法集群自动数据 解决 无法 重启
2023-09-27 14:25:31 时间

停止redis集群清除数据后重启无法自动重连问题解决方法

 

问题重现步骤

1、停止redis集群中的每个节点

用命令停止逐个节点太麻烦了,写了个shell脚本,shutdown.sh (-a 123456 是redis集群的连接密码)

redis-cli -p 7001 -a 123456 shutdown
redis-cli -p 7002 -a 123456 shutdown
redis-cli -p 7003 -a 123456 shutdown
redis-cli -p 7004 -a 123456 shutdown
redis-cli -p 7005 -a 123456 shutdown
redis-cli -p 7006 -a 123456 shutdown

执行命令 ./shutdown.sh 停止redis服务

 

2、清除每个节点产生的数据文件(nodes.conf appendonly.aof  dump.rdb ) 

执行脚本./moveRedis.sh 清除数据文件

moveRedis.sh内容为

cd redis7001
rm -rf  nodes.conf appendonly.aof  dump.rdb 
cd ..
cd redis7002
rm -rf  nodes.conf appendonly.aof  dump.rdb 
cd ..
cd redis7003
rm -rf  nodes.conf appendonly.aof  dump.rdb 
cd ..
cd redis7004
rm -rf  nodes.conf appendonly.aof  dump.rdb 
cd ..
cd redis7005
rm -rf  nodes.conf appendonly.aof  dump.rdb 
cd ..
cd redis7006
rm -rf  nodes.conf appendonly.aof  dump.rdb 

 

3、启动redis服务

 执行 ./startall.sh 逐个启动redis服务

 startall.sh脚本内容为

cd redis7001
./redis-server redis.conf
cd ..
cd redis7002
./redis-server redis.conf
cd ..
cd redis7003
./redis-server redis.conf
cd ..
cd redis7004
./redis-server redis.conf
cd ..
cd redis7005
./redis-server redis.conf
cd ..
cd redis7006
./redis-server redis.conf

 

4、创建集群

 进入redis-trib.rb所在目录执行如下命令创建集群

./redis-trib.rb  create --replicas  1  192.169.1.71:7001  192.169.1.71:7002  192.169.1.71:7003  192.169.1.71:7004  192.169.1.71:7005  192.169.1.71:7006

 

程序报错

 以上重现过程程序都是启动着的,redis集群服务起来后redisson并没有自动重连,查看日志发现有如下报错

org.redisson.client.RedisException: MOVED redirection loop detected. Node //192.169.2.238:9511 has further redirect to //192.169.2.238:9511
    at org.redisson.command.CommandAsyncService.checkAttemptFuture(CommandAsyncService.java:865)
    at org.redisson.command.CommandAsyncService$10.operationComplete(CommandAsyncService.java:673)
    at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:511)
    at io.netty.util.concurrent.DefaultPromise.notifyListeners0(DefaultPromise.java:504)
    at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:483)
    at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:424)
    at io.netty.util.concurrent.DefaultPromise.tryFailure(DefaultPromise.java:121)
    at org.redisson.misc.RedissonPromise.tryFailure(RedissonPromise.java:108)
    at org.redisson.client.protocol.CommandData.tryFailure(CommandData.java:78)
    at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:313)
    at org.redisson.client.handler.CommandDecoder.decodeCommand(CommandDecoder.java:128)
    at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:108)
    at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:489)
    at io.netty.handler.codec.ReplayingDecoder.callDecode(ReplayingDecoder.java:366)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
    at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
    at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
    at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:647)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:582)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:499)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:461)
    at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Thread.java:748)

解决方案

 最开始怀疑是redisson版本的原因,原来是redisson-3.8.2,将版本提高至3.11.1依旧有这个问题

 然后猜测是不是和redis版本有关,将redis版本由3.2.12升至4.0.14后,问题依然存在

 既然和外部无关,那就只能从程序上优化了

 

在使用到RedissonClient的方法中捕获异常,一旦出现异常,重新获取一次RedissonClient

 需要注意的是

 手动调用加了@Bean注解的方法无效,需要再写一个用于手动调用的获取RedissonClient的方法

 

 完整代码如下

package com.xiaonian.middleware.redis;

import com.xiaonian.util.StrUtil;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

/**
 * Redisson管理类
 * 连接redis2(缓存redis)
 * @author xiaonian
 * @date 2019/6/26 10:41
 * @version v2.0.0
 */
@Configuration
@Component
public class RedissonManager {

    /**redis集群节点*/
    @Value(value = "${spring.redis.cluster.nodes:#{null}}")
    private  String cluster;
    /**redis密码*/
    @Value("${spring.redis.password:#{null}}")
    private String password;
    @Value("${spring.redis.host:#{null}}")
    /**redis单机节点主机*/
    private String host;
    /**redis单机节点端口*/
    @Value("${spring.redis.host:#{null}}")
    private String port;
    /**最大连接数*/
    @Value("${redisson.pool.max.active:30}")
    private int MaxPoolSize;

    @Bean
    public RedissonClient getRedisson() {
        return loadRedisson();
    }

    public RedissonClient loadRedisson(){
        RedissonClient redisson = null;
        Config config = new Config();
        //单节点
        if(!StrUtil.isEmpty(host)){
            config.useSingleServer().
                    setAddress("redis://"+host+":"+port)
                    .setPassword(password)
                    .setConnectionPoolSize(MaxPoolSize)
                    //最小空闲连接
                    .setConnectionMinimumIdleSize(0);
            redisson = Redisson.create(config);
        }else{
            //集群节点
            String[] nodes = cluster.split(",");
            //redisson版本是3.5,集群的ip前面要加上“redis://”,不然会报错,3.2版本可不加
            for(int i=0;i<nodes.length;i++){
                nodes[i] = "redis://"+nodes[i];
            }
            //这是用的集群server
            config.useClusterServers()
                    //设置集群状态扫描时间2000
                    .setScanInterval(2000)
                    .addNodeAddress(nodes)
                    .setPassword(password)
                    .setMasterConnectionPoolSize(MaxPoolSize)
                    //最小空闲连接
                    .setMasterConnectionMinimumIdleSize(0);
            redisson = Redisson.create(config);
//            System.out.println(config.);
            //可通过打印redisson.getConfig().toJSON().toString()来检测是否配置成功
        }
        return redisson;
    }

    public RedissonClient retryGetRedisson() {
       return loadRedisson();
    }
}