当我们在做数据库分库分表或者是分布式缓存时,不可避免的都会遇到一个问题:

如何将数据均匀的分散到各个节点中,并且尽量的在加减节点时能使受影响的数据最少。

Hash 取模

随机放置就不说了,会带来很多问题。通常最容易想到的方案就是 hash 取模了。

可以将传入的 Key 按照 index = hash(key) % N 这样来计算出需要存放的节点。其中 hash 函数是一个将字符串转换为正整数的哈希映射方法,N 就是节点的数量。

这样可以满足数据的均匀分配,但是这个算法的容错性和扩展性都较差。

比如增加或删除了一个节点时,所有的 Key 都需要重新计算,显然这样成本较高,为此需要一个算法满足分布均匀同时也要有良好的容错性和拓展性。

一致 Hash 算法

一致 Hash 算法是将所有的哈希值构成了一个环,其范围在 0 ~ 2^32-1。如下图:

之后将各个节点散列到这个环上,可以用节点的 IP、hostname 这样的唯一性字段作为 Key 进行 hash(key),散列之后如下:

之后需要将数据定位到对应的节点上,使用同样的 hash 函数 将 Key 也映射到这个环上。

这样按照顺时针方向就可以把 k1 定位到 N1节点,k2 定位到 N3节点,k3 定位到 N2节点

大专栏  一致性 Hash 算法分析

容错性

这时假设 N1 宕机了:

依然根据顺时针方向,k2 和 k3 保持不变,只有 k1 被重新映射到了 N3。这样就很好的保证了容错性,当一个节点宕机时只会影响到少少部分的数据。

拓展性

当新增一个节点时:

在 N2 和 N3 之间新增了一个节点 N4 ,这时会发现受印象的数据只有 k3,其余数据也是保持不变,所以这样也很好的保证了拓展性。

虚拟节点

到目前为止该算法依然也有点问题:

当节点较少时会出现数据分布不均匀的情况:

这样会导致大部分数据都在 N1 节点,只有少量的数据在 N2 节点。

为了解决这个问题,一致哈希算法引入了虚拟节点。将每一个节点都进行多次 hash,生成多个节点放置在环上称为虚拟节点:

计算时可以在 IP 后加上编号来生成哈希值。

这样只需要在原有的基础上多一步由虚拟节点映射到实际节点的步骤即可让少量节点也能满足均匀性。

号外

最近在总结一些 Java 相关的知识点,感兴趣的朋友可以一起维护。

地址: https://github.com/crossoverJie/Java-Interview

最新文章

  1. Spearman秩相关系数和Pearson皮尔森相关系数
  2. centos 6.8 安装 nginx-1.11.4
  3. TCP/IP详解--发送ACK和RST的场景
  4. Unity3D 发布无边框exe
  5. 在VC项目中附加包含目录
  6. 解决ScrollView与ListView事件冲突
  7. javascript 关于一周前一个月前的处理方法
  8. hdfs经常使用命令
  9. 玩转html5(五)---月球绕着地球转,地球绕着太阳转(canvas实现,同样可以动哦)
  10. Python学习一:Python简介
  11. pytest(1)
  12. Setting NLS_LANG Value for Oracle
  13. python_08 函数式编程、高阶函数、map、filter、reduce函数、内置函数
  14. EF 控制code-first生成的数据库表名的单复数
  15. 分形之花篮(Flower Basket)
  16. eclipse上搭建mybatis
  17. 30. Substring with Concatenation of All Words *HARD*
  18. 2018.09.29 bzoj3039: 玉蟾宫(悬线法)
  19. 【.NET】AutoMapper学习记录
  20. Hadoop Hive 中的排序 Order by ,Sort by ,Distribute by以及 Cluster By

热门文章

  1. upstream实现内网网站在公网访问
  2. NSPredicate 应用1
  3. 2019ICPC 上海网络赛 L. Digit sum(二维树状数组+区间求和)
  4. Juptyer中的图表显示参数
  5. 17.3.15---C语言详解FILE文件操作
  6. web前端——CSS详解
  7. 用原生socket发送HTTP数据包
  8. addEventListener和onclick的区别
  9. 在Linux中#!/usr/bin/python之后把后面的代码当成程序来执行。 但是在windows中用IDLE编程的话#后面的都是注释,之后的代码都被当成文本了。 该怎么样才能解决这个问题呢?
  10. 在Linux生成公钥后,使用git拉代码仍然需要密码的问题