ShardedJedisPool xml配置:
<bean id="shardedJedisPool" class="redis.clients.jedis.ShardedJedisPool"> <constructor-arg index="0"> <bean class="redis.clients.jedis.JedisPoolConfig"></bean> </constructor-arg> <constructor-arg index="1"> <list> <bean class="redis.clients.jedis.JedisShardInfo"> <constructor-arg name="host" value="192.168.233.8"/> <constructor-arg name="port" value="6379"/> </bean> <bean class="redis.clients.jedis.JedisShardInfo"> <constructor-arg name="host" value="192.168.233.8"/> <constructor-arg name="port" value="6381"/> </bean> <bean class="redis.clients.jedis.JedisShardInfo"> <constructor-arg name="host" value="192.168.233.8"/> <constructor-arg name="port" value="6382"/> </bean> </list> </constructor-arg> </bean>
xml配置对应的构造方法:
public class ShardedJedisPool extends Pool<ShardedJedis> { public ShardedJedisPool(final GenericObjectPoolConfig poolConfig, List<JedisShardInfo> shards) { this(poolConfig, shards, Hashing.MURMUR_HASH); } }
ShardedJedisPool使用示例:
ShardedJedisPool pool = ctx.getBean(ShardedJedisPool.class); ShardedJedis jedis = pool.getResource(); String zhang = jedis.get("zhang"); jedis.close();
ShardedJedisPool.getResource 的调用栈:
代码分析:
//类 redis.clients.util.Sharded<R, S extends ShardInfo<R>> private final Map<ShardInfo<R>, R> resources = new LinkedHashMap<ShardInfo<R>, R>(); private void initialize(List<S> shards) { nodes = new TreeMap<Long, S>(); //shards是xml中配置的redis.clients.jedis.JedisShardInfo的list for (int i = 0; i != shards.size(); ++i) { final S shardInfo = shards.get(i); //没有为JedisShardInfo设置name,所以执行if分支,weight默认为1 //取 SHARD-0-NODE-0 ~ SHARD-0-NODE-159 哈希值 //取 SHARD-1-NODE-0 ~ SHARD-1-NODE-159 哈希值 //取 SHARD-2-NODE-0 ~ SHARD-2-NODE-159 哈希值 //把(哈希值->JedisShardInfo)键值对放入nodes中 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); } //添加到map中,键为JedisShardInfo,值为Jedis resources.put(shardInfo, shardInfo.createResource()); } }
JedisShardInfo.createResource:
//省略其他代码 public class JedisShardInfo extends ShardInfo<Jedis> { @Override public Jedis createResource() { return new Jedis(this); } }
存取一个键时,根据键获取一个JedisShardInfo,以get为例:
public S getShardInfo(byte[] key) { //nodes是TreeMap,由红黑树实现,是按键值排好序的map,默认为升序 //假定 algo.hash(key) 的值为10086,该行代码是取出键大于10086的所有键值对 SortedMap<Long, S> tail = nodes.tailMap(algo.hash(key)); //如果不存在,则取第一个键值对的JedisShardInfo if (tail.isEmpty()) { return nodes.get(nodes.firstKey()); } //如果存在这样的键值对,则返回第一个键值对中的JedisShardInfo return tail.get(tail.firstKey()); }
Sharded类中有2个map,TreeMap<Long, S> nodes和Map<ShardInfo<R>, R> resources,
运行时具体是:TreeMap<Long, JedisShardInfo>和Map<JedisShardInfo, Jedis>。
分析以上代码可知,首先计算出 "SHARD-i-NODE-n" 的哈希值,预先生成一颗红黑树,即填充nodes。
当存取键值对时,计算键的哈希值,然后从红黑树上摘下比该值大的第一个节点上的JedisShardInfo,随后从resources取出Jedis。
假定有红黑树如下: