利用线性同余的一致性 Hash 算法

x33g5p2x  于2022-02-07 转载在 其他  
字(2.1k)|赞(0)|评价(0)|浏览(262)

一 算法内容

以下是线性同余的一致性 Hash 算法的全部代码。

输入参数分别是 64 位的 key 和桶的数量(一般对于服务节点的数量),输出一个桶的编号(从0开始)。

1 代码

  1. package consistenthash;
  2. /**
  3. * @className: JumpConsistentHash
  4. * @description: 利用线性同余的一致性 Hash 算法
  5. * @date: 2022/2/1
  6. * @author: 贝医
  7. */
  8. public class JumpConsistentHash {
  9. private static final long UNSIGNED_MASK = 0x7fffffffffffffffL;
  10. private static final long JUMP = 1L << 31;
  11. private static final long CONSTANT = Long
  12. .parseUnsignedLong("2862933555777941757");
  13. private JumpConsistentHash() {
  14. throw new AssertionError(
  15. "No com.github.ssedano.hash.JumpConsistentHash instances for you!");
  16. }
  17. /**
  18. * @param o 对象
  19. * @param buckets 桶的个数
  20. * @return int 节点
  21. */
  22. public static int jumpConsistentHash(final Object o, final int buckets) {
  23. return jumpConsistentHash(o.hashCode(), buckets);
  24. }
  25. /**
  26. * @param key 键
  27. * @param buckets 桶的个数
  28. * @return the hash of the key
  29. * @throws IllegalArgumentException if buckets is less than 0
  30. */
  31. public static int jumpConsistentHash(final long key, final int buckets) {
  32. checkBuckets(buckets);
  33. long k = key;
  34. long b = -1;
  35. long j = 0;
  36. while (j < buckets) {
  37. b = j;
  38. k = k * CONSTANT + 1L;
  39. j = (long) ((b + 1L) * (JUMP / toDouble((k >>> 33) + 1L)));
  40. }
  41. return (int) b;
  42. }
  43. private static void checkBuckets(final int buckets) {
  44. if (buckets < 0) {
  45. throw new IllegalArgumentException("Buckets cannot be less than 0");
  46. }
  47. }
  48. private static double toDouble(final long n) {
  49. double d = n & UNSIGNED_MASK;
  50. if (n < 0) {
  51. d += 0x1.0p63;
  52. }
  53. return d;
  54. }
  55. public static void main(String[] args) {
  56. for (int i = 0; i < 35; i++) {
  57. int node = jumpConsistentHash(i, 7);
  58. System.out.println("选中节点为" + node);
  59. }
  60. }
  61. }

2 测试

  1. 选中节点为:0
  2. 选中节点为:6
  3. 选中节点为:6
  4. 选中节点为:3
  5. 选中节点为:1
  6. 选中节点为:4
  7. 选中节点为:5
  8. 选中节点为:0
  9. 选中节点为:4
  10. 选中节点为:2
  11. 选中节点为:6
  12. 选中节点为:5
  13. 选中节点为:1
  14. 选中节点为:0
  15. 选中节点为:5
  16. 选中节点为:4
  17. 选中节点为:2
  18. 选中节点为:4
  19. 选中节点为:4
  20. 选中节点为:6
  21. 选中节点为:0
  22. 选中节点为:3
  23. 选中节点为:6
  24. 选中节点为:3
  25. 选中节点为:1
  26. 选中节点为:5
  27. 选中节点为:0
  28. 选中节点为:6
  29. 选中节点为:2
  30. 选中节点为:5
  31. 选中节点为:3
  32. 选中节点为:6
  33. 选中节点为:1
  34. 选中节点为:0
  35. 选中节点为:6
  36. Process finished with exit code 0

二 适用场景

该算法适用于分布式存储产品,而不太适合用于缓存类型的产品。因为当有节点不可用时, jump consistent hash 算法用存活节点分担不可用节点能力不强,当有节点失效要把数据迁移到其他节点时,会造成大量的数据被移动。但在分布式存储产品中,主节点不可用时会把访问主节点的请求路由到备节点,key 的分布不会有变化。

该算法适合用在分布式系统中根据 key 来选择被分配到的服务的场景。每次新增服务节点时,只有 1/n 的 key 会变动,不会因为扩容或缩容的瞬间造成大部分缓存失效。

三 缺点

和其他一致性 Hash 算法相比,如果中间的桶失效,则该算法是不能像其他一致性算法一样把失效的数据均匀分配到其他节点的,只能找到一个新的节点替换。

四 优点

不用存储过多节点信息,计算量小,运行快速、代码短,易于实现。

五 参考

一致性哈希算法(三)- 跳跃一致性哈希法 | 春水煎茶 - 王超的个人博客

GitHub - ssedano/jump-consistent-hash: Java implementation of the jump consistent hash

相关文章