淮北论坛网官网百度seo关键词排名优化
最近在使用 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 {@Testpublic 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 编码格式的字符串。