我对一致性hash算法的理解

     一致性hash算法相对传统的按照机器数目取模的算法,最大的好处在于动态的进行机器的添加和摘除可以不引起大面积的缓存失效。

    一致性hash的动态增加减少节点的缓存变化可以参考博客:http://www.blogjava.net/hello-yun/archive/2012/10/10/389289.html

     我要说的是针对redis的默认的分片按照加入的机器列表的顺序来进行散列,这样如果我们动态的将中间的任意一个节点去掉,这个时候由于每个节点都是按照索引值作为一个索引值作为hash因素来进行位置计算的,这样顺序就会全部乱了。

     正确的做法是利用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的最里面的生成散列键的方法如下:

    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就不会存在摘掉节点或者增加节点大量缓存失效的问题了。

  个人的一点愚见,欢迎指教。



你可能感兴趣的:(我对一致性hash算法的理解)