停止redis集群后清除數據重啟,Redisson無法自動重連問題解決方法


停止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();
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM