Redis_RedisCluster set 方法跟踪纪要

 

最近在使用  JedisCluster 时,  对 集群模式下的  Redis key 的设置策略比较感兴趣,跟踪了一下执行 set 方法的 主要源码,特此记录一下。

 

跟踪的源码版本 

pom.xml

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
 

追踪的源头代码:

package com.yaobaling.td.blacklist.redis;

import com.yaobaling.td.blacklist.config.ConfigCenter;
import org.junit.Test;

/**
 * Created by szh on 2018/10/11.
 */
public class RedisClusterTest {

    @Test
    public void testCluster() throws Exception {

        RedisCluster redisCluster = new RedisCluster(ConfigCenter.getInstance().getRedisConfig());

        redisCluster.getClusterConn().set("test_string", "2222");

        String tmp = redisCluster.getClusterConn().get("test_string");
        System.out.println(tmp);
    }
}

 

我们主要追踪这一行代码:

redisCluster.getClusterConn().set("test_string", "2222");

 

首先,点击 ctrl 点击 set 方法,

可以看到执行了,如下代码:

public String set(final String key, final String value) {
        return (String)(new JedisClusterCommand<String>(this.connectionHandler, this.maxAttempts) {
            public String execute(Jedis connection) {
                return connection.set(key, value);
            }
        }).run(key);
    }

 

我们再跟中下 run  方法:

 

可以看到方法内部,主要执行如下方法 : 

this.runWithRetries(SafeEncoder.encode(key), this.maxAttempts, false, false);

 

 

 

 

 我们继续 跟踪  runWithRetries  方法  与   SafeEncoder.encode(key)  方法:

 

 

-------------------------------------------------------------------------

首先我们跟踪   runWithRetries  方法 :

 

private T runWithRetries(byte[] key, int attempts, boolean tryRandomNode, boolean asking) {
        if(attempts <= 0) {
            throw new JedisClusterMaxRedirectionsException("Too many Cluster redirections?");
        } else {
            Jedis connection = null;

            Object var7;
            try {
                if(asking) {
                    connection = (Jedis)this.askConnection.get();
                    connection.asking();
                    asking = false;
                } else if(tryRandomNode) {
                    connection = this.connectionHandler.getConnection();
                } else {
                    connection = this.connectionHandler.getConnectionFromSlot(JedisClusterCRC16.getSlot(key));
                }

                Object var6 = this.execute(connection);
                return var6;
            } catch (JedisNoReachableClusterNodeException var13) {
                throw var13;
            } catch (JedisConnectionException var14) {
                this.releaseConnection(connection);
                connection = null;
                if(attempts <= 1) {
                    this.connectionHandler.renewSlotCache();
                    throw var14;
                }

                var7 = this.runWithRetries(key, attempts - 1, tryRandomNode, asking);
            } catch (JedisRedirectionException var15) {
                if(var15 instanceof JedisMovedDataException) {
                    this.connectionHandler.renewSlotCache(connection);
                }

                this.releaseConnection(connection);
                connection = null;
                if(var15 instanceof JedisAskDataException) {
                    asking = true;
                    this.askConnection.set(this.connectionHandler.getConnectionFromNode(var15.getTargetNode()));
                } else if(!(var15 instanceof JedisMovedDataException)) {
                    throw new JedisClusterException(var15);
                }

                var7 = this.runWithRetries(key, attempts - 1, false, asking);
                return var7;
            } finally {
                this.releaseConnection(connection);
            }

            return var7;
        }
    }

可以看到 4个参数 分别为以下4个:

runWithRetries(byte[] key, int attempts, boolean tryRandomNode, boolean asking)

 

byte[] key :   SafeEncoder.encode(key)

 int attempts :   this.maxAttempts

boolean tryRandomNode : false

boolean asking : false

 

我们再跟踪下 

this.connectionHandler.getConnectionFromSlot(JedisClusterCRC16.getSlot(key));

这个方法,this.connectionHandler.getConnectionFromSlot(JedisClusterCRC16.getSlot(key)); 

从这里,我们可以看到,获取指定的key 存放的位置,是从一个暂存池中获取到指定的连接的。

 

 

 

this.connectionHandler.getConnectionFromSlot(JedisClusterCRC16.getSlot(key)) :

ctrl 点击来,可以看到这是个 抽象类:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package redis.clients.jedis;

import java.io.Closeable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.exceptions.JedisConnectionException;

public abstract class JedisClusterConnectionHandler implements Closeable {
    protected final JedisClusterInfoCache cache;

    public JedisClusterConnectionHandler(Set<HostAndPort> nodes, GenericObjectPoolConfig poolConfig, int connectionTimeout, int soTimeout, String password) {
        this.cache = new JedisClusterInfoCache(poolConfig, connectionTimeout, soTimeout, password);
        this.initializeSlotsCache(nodes, poolConfig, password);
    }

    abstract Jedis getConnection();

    abstract Jedis getConnectionFromSlot(int var1);

    public Jedis getConnectionFromNode(HostAndPort node) {
        return this.cache.setupNodeIfNotExist(node).getResource();
    }

    public Map<String, JedisPool> getNodes() {
        return this.cache.getNodes();
    }

    private void initializeSlotsCache(Set<HostAndPort> startNodes, GenericObjectPoolConfig poolConfig, String password) {
        Iterator var4 = startNodes.iterator();

        while(var4.hasNext()) {
            HostAndPort hostAndPort = (HostAndPort)var4.next();
            Jedis jedis = new Jedis(hostAndPort.getHost(), hostAndPort.getPort());
            if(password != null) {
                jedis.auth(password);
            }

            try {
                this.cache.discoverClusterNodesAndSlots(jedis);
                break;
            } catch (JedisConnectionException var11) {
                ;
            } finally {
                if(jedis != null) {
                    jedis.close();
                }

            }
        }

    }

    public void renewSlotCache() {
        this.cache.renewClusterSlots((Jedis)null);
    }

    public void renewSlotCache(Jedis jedis) {
        this.cache.renewClusterSlots(jedis);
    }

    public void close() {
        this.cache.reset();
    }
}

 

 

ctrl + alt + b 看下抽象方法的具体实现:

abstract Jedis getConnectionFromSlot(int var1);

可以看到具体的方法,由以下类进行实现:

package redis.clients.jedis;
public class JedisSlotBasedConnectionHandler extends JedisClusterConnectionHandler {
 public Jedis getConnectionFromSlot(int slot) {
        JedisPool connectionPool = this.cache.getSlotPool(slot);
        if(connectionPool != null) {
            return connectionPool.getResource();
        } else {
            this.renewSlotCache();
            connectionPool = this.cache.getSlotPool(slot);
            return connectionPool != null?connectionPool.getResource():this.getConnection();
        }
    }

 

 

----------------------------------------------------------------

再跟踪下  

SafeEncoder.encode(key)  
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package redis.clients.util;

import java.io.UnsupportedEncodingException;
import redis.clients.jedis.exceptions.JedisDataException;
import redis.clients.jedis.exceptions.JedisException;

public final class SafeEncoder {
    private SafeEncoder() {
        throw new InstantiationError("Must not instantiate this class");
    }

    public static byte[][] encodeMany(String... strs) {
        byte[][] many = new byte[strs.length][];

        for(int i = 0; i < strs.length; ++i) {
            many[i] = encode(strs[i]);
        }

        return many;
    }

    public static byte[] encode(String str) {
        try {
            if(str == null) {
                throw new JedisDataException("value sent to redis cannot be null");
            } else {
                return str.getBytes("UTF-8");
            }
        } catch (UnsupportedEncodingException var2) {
            throw new JedisException(var2);
        }
    }

    public static String encode(byte[] data) {
        try {
            return new String(data, "UTF-8");
        } catch (UnsupportedEncodingException var2) {
            throw new JedisException(var2);
        }
    }
}

 

 

可以看到,主要处理 是 将字符串转换为  UTF-8 编码格式的字符串。

 

 

 

 

由以上的代码得出,实际上集群模式下,执行Redis 指令,是根据 redis 的 key 做一定处理后,从 连接池中选择 满足条件的 指定连接 进行操作的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值