分片链接sharejedis的流程源码分析:
创建sharejedis有两种方法,一个是通过池的方式shardedJedisPool.getResource(),这里面底层的实现涉及到java通用池的源码分析,后续有机会再分析,先说说普通的通过构造方法创建的流程源码。
public ShardedJedis(List
super(shards, algo, keyTagPattern);
}
--通过上面的构造方法可以看出,创建一个sharejedis对象要传入一个JedisShardInfo列表,还有一个哈希算法Hashingalgo,Pattern keyTagPattern则为对key进行哈希的限制条件。其中后两者一般都采用默认值,主要是JedisShardInfo> shards,其中JedisShardInfo里面填充了创建redis链接需要的各种信息,比如ip,端口等,这是我们分析流程的主线,从构造方法可以看到调用了父类BinaryShardedJedis的构造方法来实现。
publicBinaryShardedJedis(List
super(shards, algo, keyTagPattern);
}
--而BinaryShardedJedis继续调用了它的父类Sharded的构造方法实现
public Sharded(List shards,Hashing algo, Pattern tagPattern) {
this.algo = algo;
this.tagPattern = tagPattern;
initialize(shards);
}
--调用Sharded. initialize(shards);
private void initialize(Listshards) {
nodes = new TreeMap
for (int i = 0; i != shards.size(); ++i) {
final S shardInfo = shards.get(i);
if (shardInfo.getName() == null) for (int n = 0; n < 160 *shardInfo.getWeight(); n++) {
nodes.put(this.algo.hash("SHARD-" + i + "-NODE-" +n), shardInfo);
}
else for (int n = 0; n < 160 * shardInfo.getWeight(); n++) {
nodes.put(this.algo.hash(shardInfo.getName() + "*" +shardInfo.getWeight() + n), shardInfo);
}
resources.put(shardInfo, shardInfo.createResource());
}
}
--其中nodes.put(this.algo.hash(shardInfo.getName()+ "*" + shardInfo.getWeight() + n), shardInfo);和resources.put(shardInfo,shardInfo.createResource());需重点注意,前者是往TreeMap添加键值对,也就是虚拟节点(hash(key))和shardInfo的映射关系,后者是往LinkedHashMap
public Jedis createResource() {
return new Jedis(this);
}
-- return new Jedis(this);调用了jedis的一个重载构造方法
public Jedis(JedisShardInfo shardInfo) {
super(shardInfo);
}
-- Jedis调用了它的父类BinaryJedis的构造方法实现
public BinaryJedis(final JedisShardInfoshardInfo) {
client = new Client(shardInfo.getHost(), shardInfo.getPort(),shardInfo.getSsl(),
shardInfo.getSslSocketFactory(), shardInfo.getSslParameters(),
shardInfo.getHostnameVerifier());
client.setConnectionTimeout(shardInfo.getConnectionTimeout());
client.setSoTimeout(shardInfo.getSoTimeout());
client.setPassword(shardInfo.getPassword());
client.setDb(shardInfo.getDb());
}
--最终在BinaryJedis中创建了连接客户端对象client,并根据JedisShardInfo中的信息比如ip,端口,超时时长等进行了和服务端的链接工作。
当我们使用ShardedJedis对redis数据库进行读写操作时的流程如下:
Jedis jedis = shardedJedis.getShard(key);
Jedis.set(key);
Jedis.get(key);
首先,shardedJedis.getShard(key);调用了父类Sharded的源码如下
public R getShard(String key) {
return resources.get(getShardInfo(key));
}
--其中的resources就是前面介绍的Sharded.initialize()里面的LinkedHashMap,也就是存储着shardInfo和jedis的映射关系。而getShardInfo(key)的实现如下:
public S getShardInfo(byte[] key) {
SortedMap
if (tail.isEmpty()) {
return nodes.get(nodes.firstKey());
}
return tail.get(tail.firstKey());
}
--通过nodes,也就是前面介绍的Sharded.initialize()里面的TreeMap(虚拟节点(hash(key))和shardInfo的映射关系)获得hash(key)后对应的shardInfo对象,然后再通过LinkedHashMap获取shardInfo对象对应的jedis实例,然后通过这个jedis对redis进行读写操作。
而jedis的get和set操作的源码如下:
public String get(final String key) {
checkIsInMultiOrPipeline();
client.sendCommand(Protocol.Command.GET, key);
return client.getBulkReply();
}
public String set(final String key, Stringvalue) {
checkIsInMultiOrPipeline();
client.set(key, value);
return client.getStatusCodeReply();
}
用了父类BinaryJedis类中的链接客户端对象client属性进行读写操作。这样一来不但把ShardedJedis的使用流程的源码分析了一遍,也顺便把普通的jedis的操作底层源码分析了一遍。
整个ShardedJedis创建和使用流程如上所述。简单来说就是创建时创建了两个容器TreeMap和LinkedHashMap,应用时又通过这两个容器找到key对应的jedis对象进行操作。