一致性hash算法相对传统的按照机器数目取模的算法,最大的好处在于动态的进行机器的添加和摘除能够不引发大面积的缓存失效。html
一致性hash的动态增长减小节点的缓存变化能够参考博客:http://www.blogjava.net/hello-yun/archive/2012/10/10/389289.html
java
我要说的是针对redis的默认的分片按照加入的机器列表的顺序来进行散列,这样若是咱们动态的将中间的任意一个节点去掉,这个时候因为每一个节点都是按照索引值做为一个索引值做为hash因素来进行位置计算的,这样顺序就会所有乱了。node
正确的作法是利用redis.clients.jedis.JedisShardInfo的 public JedisShardInfo(String host, int port, int timeout, String name) {
this(host, port, timeout, timeout, Sharded.DEFAULT_WEIGHT);
this.name = name;
}这个构造函数把name给传递过来,这个name每一个分片要都传递成惟一的,能够是对应机器的ip和端口组成的字符串,这样当咱们动态的减去获取增长一个实例的时候,剩余的机器在一致性hash环上面的位置保持不变,摘掉的机器会把请求散列到其余的机器上面来,因为虚拟节点的存在,咱们姑且认为是彻底均匀的。redis
redis的最里面的生成散列键的方法以下:算法
private void initialize(List<S> shards) {
nodes = new TreeMap<Long, S>();
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());
}
}缓存
黑色加粗的地方是咱们传递的name,红色部分是若是不传递别名的话计算的key值,会影响在一致性hash环上面分片的位置,依赖外层的分片数量的循环,若是咱们传递name就不会存在摘掉节点或者增长节点大量缓存失效的问题了。
函数
我的的一点愚见,欢迎指教。
this