返回顶部
首页 > 资讯 > 前端开发 > VUE >如何理解一致性哈希算法
  • 510
分享到

如何理解一致性哈希算法

2024-04-02 19:04:59 510人浏览 泡泡鱼
摘要

本篇内容介绍了“如何理解一致性哈希算法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!要了解一致性哈希,首先

本篇内容介绍了“如何理解一致性哈希算法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

要了解一致性哈希,首先我们必须了解传统的哈希及其在大规模分布式系统中的局限性。简单地说,哈希就是一个键值对存储,在给定键的情况下,可以非常高效地找到所关联的值。假设我们要根据其邮政编码查找城市中的街道名称。一种最简单的实现方式是将此信息以哈希字典的形式进行存储

当数据太大而无法存储在一个节点或机器上时,问题变得更加有趣,系统中需要多个这样的节点或机器来存储它。比如,使用多个 WEB  缓存中间件的系统。那如何确定哪个 key 存储在哪个节点上?针对该问题,最简单的解决方案是使用哈希取模来确定。 给定一个 key,先对 key  进行哈希运算,将其除以系统中的节点数,然后将该 key 放入该节点。同样,在获取 key 时,对 key  进行哈希运算,再除以节点数,然后转到该节点并获取值。上述过程对应的哈希算法定义如下:

node_number = hash(key) % N # 其中 N 为节点数。

下图描绘了多节点系统中的传统的哈希取模算法,基于该算法可以实现简单的负载均衡

如何理解一致性哈希算法

一、传统哈希取模算法的局限性

下面我们来分析一下传统的哈希及其在大规模分布式系统中的局限性。这里我们直接使用我之前所写文章 布隆过滤器你值得拥有的开发利器 中定义的  SimpleHash 类,然后分别对 semlinker、kakuqo 和 test 3 个键进行哈希运算并取余,具体代码如下:

public class SimpleHash {     private int cap;     private int seed;      public SimpleHash(int cap, int seed) {         this.cap = cap;         this.seed = seed;     }      public int hash(String value) {         int result = 0;         int len = value.length();         for (int i = 0; i < len; i++) {             result = seed * result + value.charAt(i);         }         return (cap - 1) & result;     }      public static void main(String[] args) {         SimpleHash simpleHash = new SimpleHash(2 << 12, 8);         System.out.println("node_number=hash(\"semlinker\") % 3 -> " +            simpleHash.hash("semlinker") % 3);         System.out.println("node_number=hash(\"kakuqo\") % 3 -> " +            simpleHash.hash("kakuqo") % 3);         System.out.println("node_number=hash(\"test\") % 3 -> " +            simpleHash.hash("test") % 3);     } }

以上代码成功运行后,在控制台会输出以下结果:

node_number=hash("semlinker") % 3 -> 1 node_number=hash("kakuqo") % 3 -> 2 node_number=hash("test") % 3 -> 0

基于以上的输出结果,我们可以创建以下表格:

如何理解一致性哈希算法

1.1 节点减少的场景

在分布式多节点系统中,出现故障很常见。任何节点都可能在没有任何事先通知的情况下挂掉,针对这种情况我们期望系统只是出现性能降低,正常的功能不会受到影响。  对于原始示例,当节点出现故障时会发生什么?原始示例中有的 3 个节点,假设其中 1 个节点出现故障,这时节点数发生了变化,节点个数从 3 减少为  2,此时表格的状态发生了变化:

如何理解一致性哈希算法

很明显节点的减少会导致键与节点的映射关系发生变化,这个变化对于新的键来说并不会产生任何影响,但对于已有的键来说,将导致节点映射错误,以  “semlinker” 为例,变化前系统有 3 个节点,该键对应的节点编号为 1,当出现故障时,节点数减少为 2 个,此时该键对应的节点编号为 0。

1.2 节点增加的场景

在分布式多节点系统中,对于某些场景比如节日大促,就需要对服务节点进行扩容,以应对突发的流量。 对于原始示例,当增加节点会发生什么?原始示例中有的 3  个节点,假设进行扩容临时增加了 1 个节点,这时节点数发生了变化,节点个数从 3 增加为 4 个,此时表格的状态发生了变化:

如何理解一致性哈希算法

很明显节点的增加也会导致键与节点的映射关系发生变化,这个变化对于新的键来说并不会产生任何影响,但对于已有的键来说,将导致节点映射错误,同样以  “semlinker” 为例,变化前系统有 3 个节点,该键对应的节点编号为 1,当增加节点时,节点数增加为 4 个,此时该键对应的节点编号为 2。

集群中节点的数量发生变化时,之前的映射规则就可能发生变化。如果集群中每个机器提供的服务没有差别,这不会有什么影响。但对于分布式缓存这种的系统而言,映射规则失效就意味着之前缓存的失效,若同一时刻出现大量的缓存失效,则可能会出现  “缓存雪崩”,这将会造成灾难性的后果。

要解决此问题,我们必须在其余节点上重新分配所有现有键,这可能是非常昂贵的操作,并且可能对正在运行的系统产生不利影响。当然除了重新分配所有现有键的方案之外,还有另一种更好的方案即使用一致性哈希算法。

二、一致性哈希算法

一致性哈希算法在 1997  年由麻省理工学院提出,是一种特殊的哈希算法,在移除或者添加一个服务器时,能够尽可能小地改变已存在的服务请求与处理请求服务器之间的映射关系。一致性哈希解决了简单哈希算法在分布式哈希表(Distributed  Hash Table,DHT)中存在的动态伸缩等问题 。

2.1 一致性哈希算法优点

  • 可扩展性。一致性哈希算法保证了增加或减少服务器时,数据存储的改变最少,相比传统哈希算法大大节省了数据移动的开销 。

  • 更好地适应数据的快速增长。采用一致性哈希算法分布数据,当数据不断增长时,部分虚拟节点中可能包含很多数据、造成数据在虚拟节点上分布不均衡,此时可以将包含数据多的虚拟节点分裂,这种分裂仅仅是将原有的虚拟节点一分为二、不需要对全部的数据进行重新哈希和划分。

虚拟节点分裂后,如果物理服务器的负载仍然不均衡,只需在服务器之间调整部分虚拟节点的存储分布。这样可以随数据的增长而动态的扩展物理服务器的数量,且代价远比传统哈希算法重新分布所有数据要小很多。

2.2 一致性哈希算法与哈希算法的关系

一致性哈希算法是在哈希算法基础上提出的,在动态变化的分布式环境中,哈希算法应该满足的几个条件:平衡性、单调性和分散性。

  • 平衡性:是指 hash 的结果应该平均分配到各个节点,这样从算法上解决了负载均衡问题。

  • 单调性:是指在新增或者删减节点时,不影响系统正常运行。

  • 分散性:是指数据应该分散地存放在分布式集群中的各个节点(节点自己可以有备份),不必每个节点都存储所有的数据。

三、一致性哈希算法原理

一致性哈希算法通过一个叫作一致性哈希环的数据结构实现。这个环的起点是 0,终点是 2^32 - 1,并且起点与终点连接,故这个环的整数分布范围是 [0,  2^32-1],如下图所示:

如何理解一致性哈希算法

3.1 将对象放置到哈希环

假设我们有 "semlinker"、"kakuqo"、"lolo"、"fer" 四个对象,分别简写为 o1、o2、o3 和  o4,然后使用哈希函数计算这个对象的 hash 值,值的范围是 [0, 2^32-1]:

如何理解一致性哈希算法

图中对象的映射关系如下:

hash(o1) = k1; hash(o2) = k2; hash(o3) = k3; hash(o4) = k4;

3.2 将服务器放置到哈希环

接着使用同样的哈希函数,我们将服务器也放置到哈希环上,可以选择服务器的 IP  或主机名作为键进行哈希,这样每台服务器就能确定其在哈希环上的位置。这里假设我们有 3 台缓存服务器,分别为 cs1、cs2 和 cs3:

如何理解一致性哈希算法

图中服务器的映射关系如下:

hash(cs1) = t1; hash(cs2) = t2; hash(cs3) = t3; # Cache Server

3.3 为对象选择服务器

将对象和服务器都放置到同一个哈希环后,在哈希环上顺时针查找距离这个对象的 hash 值最近的机器,即是这个对象所属的机器。 以 o2  对象为例,顺序针找到最近的机器是 cs2,故服务器 cs2 会缓存 o2 对象。而服务器 cs1 则缓存 o1,o3 对象,服务器 cs3 则缓存 o4  对象。

如何理解一致性哈希算法

3.4 服务器增加的情况

假设由于业务需要,我们需要增加一台服务器 cs4,经过同样的 hash 运算,该服务器最终落于 t1 和 t2 服务器之间,具体如下图所示:

图片

对于上述的情况,只有 t1 和 t2 服务器之间的对象需要重新分配。在以上示例中只有 o3 对象需要重新分配,即它被重新到 cs4  服务器。在前面我们已经分析过,如果使用简单的取模方法,当新添加服务器时可能会导致大部分缓存失效,而使用一致性哈希算法后,这种情况得到了较大的改善,因为只有少部分对象需要重新分配。

3.5 服务器减少的情况

假设 cs3 服务器出现故障导致服务下线,这时原本存储于 cs3 服务器的对象 o4,需要被重新分配至 cs2  服务器,其它对象仍存储在原有的机器上。

如何理解一致性哈希算法

3.6 虚拟节点

到这里一致性哈希的基本原理已经介绍完了,但对于新增服务器的情况还存在一些问题。新增的服务器 cs4 只分担了 cs1 服务器的负载,服务器 cs2 和  cs3 并没有因为 cs4 服务器的加入而减少负载压力。如果 cs4 服务器的性能与原有服务器的性能一致甚至可能更高,那么这种结果并不是我们所期望的。

针对这个问题,我们可以通过引入虚拟节点来解决负载不均衡的问题。即将每台物理服务器虚拟为一组虚拟服务器,将虚拟服务器放置到哈希环上,如果要确定对象的服务器,需先确定对象的虚拟服务器,再由虚拟服务器确定物理服务器。

如何理解一致性哈希算法

图中 o1 和 o2 表示对象,v1 ~ v6 表示虚拟服务器,s1 ~ s3 表示物理服务器。

四、一致性哈希算法实现

这里我们只介绍不带虚拟节点的一致性哈希算法实现:

import java.util.SortedMap; import java.util.TreeMap;  public class ConsistentHashingWithoutVirtualNode {     //待添加入Hash环的服务器列表     private static String[] servers = {"192.168.0.1:8888", "192.168.0.2:8888",        "192.168.0.3:8888"};      //key表示服务器的hash值,value表示服务器     private static SortedMap<Integer, String> sortedMap = new TreeMap<Integer, String>();      //程序初始化,将所有的服务器放入sortedMap中     static {         for (int i = 0; i < servers.length; i++) {             int hash = getHash(servers[i]);             System.out.println("[" + servers[i] + "]加入集合中, 其Hash值为" + hash);             sortedMap.put(hash, servers[i]);         }     }      //得到应当路由到的结点     private static String getServer(String key) {         //得到该key的hash值         int hash = getHash(key);         //得到大于该Hash值的所有Map         SortedMap<Integer, String> subMap = sortedMap.tailMap(hash);         if (subMap.isEmpty()) {             //如果没有比该key的hash值大的,则从第一个node开始             Integer i = sortedMap.firsTKEy();             //返回对应的服务器             return sortedMap.get(i);         } else {             //第一个Key就是顺时针过去离node最近的那个结点             Integer i = subMap.firstKey();             //返回对应的服务器             return subMap.get(i);         }     }      //使用FNV1_32_HASH算法计算服务器的Hash值     private static int getHash(String str) {         final int p = 16777619;         int hash = (int) 2166136261L;         for (int i = 0; i < str.length(); i++)             hash = (hash ^ str.charAt(i)) * p;         hash += hash << 13;         hash ^= hash >> 7;         hash += hash << 3;         hash ^= hash >> 17;         hash += hash << 5;          // 如果算出来的值为负数则取其绝对值         if (hash < 0)             hash = Math.abs(hash);         return hash;     }      public static void main(String[] args) {         String[] keys = {"semlinker", "kakuqo", "fer"};         for (int i = 0; i < keys.length; i++)             System.out.println("[" + keys[i] + "]的hash值为" + getHash(keys[i])                     + ", 被路由到结点[" + getServer(keys[i]) + "]");     }  }

以上代码成功运行后,在控制台会输出以下结果:

[192.168.0.1:8888]加入集合中, 其Hash值为1326271016 [192.168.0.2:8888]加入集合中, 其Hash值为1132535844 [192.168.0.3:8888]加入集合中, 其Hash值为115798597  [semlinker]的hash值为1549041406, 被路由到结点[192.168.0.3:8888] [kakuqo]的hash值为463104755, 被路由到结点[192.168.0.2:8888] [fer]的hash值为1677150790, 被路由到结点[192.168.0.3:8888]

“如何理解一致性哈希算法”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: 如何理解一致性哈希算法

本文链接: https://lsjlt.com/news/83767.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 如何理解一致性哈希算法
    本篇内容介绍了“如何理解一致性哈希算法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!要了解一致性哈希,首先...
    99+
    2024-04-02
  • 如何理解一致性哈希
    这篇文章主要讲解了“如何理解一致性哈希”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何理解一致性哈希”吧!一技能:哈希算法分组韩信的一技能哈希算法:将士兵...
    99+
    2024-04-02
  • 一篇文章读懂Java哈希与一致性哈希算法
    目录哈希 Hash 算法介绍分布式存储场景场景描述:实现思路:缺点:一致性Hash算法节点增加场景节点减少场景节点分布不均匀虚拟节点增加节点节点减少总结哈希 Hash 算法介绍 哈希...
    99+
    2024-04-02
  • Python小知识 - 一致性哈希算法
    一致性哈希算法 一致性哈希算法(Consistent Hashing Algorithm)是用于解决分布式系统中节点增减比较频繁的问题。它的思想是,将数据映射到0~2^64-1的哈希空间中,并通...
    99+
    2023-09-16
    Python YYDS
  • 如何用PHP实现分布算法之一致性哈希算法
    目录传统算法缺陷算法思想算法实现总结传统算法缺陷 对于服务器分布,我们要考虑的东西有如下三点:数据平均分布,查找定位准确,降低宕机影响。 传统算法一般是将数据的键用算法映射出数字,对...
    99+
    2024-04-02
  • 详解Java分布式系统中一致性哈希算法
    目录业务场景使用Hash取模的问题1.负载均衡2.分库分表基本思想原理如何提高容错性和扩展性的1. 新增服务器节点2. 删除服务器节点Hash环的数据倾斜问题总结业务场景 近年来B2...
    99+
    2024-04-02
  • 怎么使用PHP实现分布算法之一致性哈希算法
    这篇文章主要介绍怎么使用PHP实现分布算法之一致性哈希算法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!传统算法缺陷对于服务器分布,我们要考虑的东西有如下三点:数据平均分布,查找定位准确,降低宕机影响。传统算法一般是...
    99+
    2023-06-15
  • 如何理解哈希算法类型hash-identifier
    这篇文章给大家介绍如何理解哈希算法类型hash-identifier,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。识别哈希算法类型hash-identifierhash-identifier是一款哈希算法识别工具。通过...
    99+
    2023-06-05
  • 详解Golang官方中的一致性哈希组件
    目录背景一致性哈希算法原理改进实现方式结构和接口添加节点重置节点获取Key对应的节点总结背景 在分布式缓存中,我们需要通过一组缓存节点来提高我们的缓存容量。比如我们有3个Redis节...
    99+
    2023-05-14
    Golang一致性哈希算法 Golang一致性哈希组件 Golang一致性哈希 Golang 哈希
  • Java数据结构哈希算法之哈希桶方式解决哈希冲突
    一. 实现形式一(键值对只能为整数) 我们可以先实现一个比较简单的哈希表,使用java中解决哈希冲突的方法,即哈希桶(开散列)方式实现,其中注意: 可以使用内部类方式定义节...
    99+
    2024-04-02
  • 一致性哈希概念与Python的简单实现
    好像从开始接触Zookeeper的时候就知道了有一致性哈希这东西。。。。不过倒是一直都没有去了解这到底是个啥东西。。。只是知道它在分布式系统设计中有十分重要的作用。。。。 好了,接下来用举例子的方式来说一下一致性哈希到底有啥用吧。。。场...
    99+
    2023-01-31
    概念 简单 一致性哈希
  • Java编码算法与哈希算法如何使用
    本篇内容主要讲解“Java编码算法与哈希算法如何使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java编码算法与哈希算法如何使用”吧!一、编码算法1.什么是编码ASCII 码就是一种编码,字...
    99+
    2023-07-04
  • Golang官方中的一致性哈希组件怎么实现
    这篇“Golang官方中的一致性哈希组件怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Golang官方中的一致性哈希...
    99+
    2023-07-05
  • 分布式缓存负载均衡的规则处理:虚拟节点对一致性哈希的改进 采用固定哈希算法平衡负载
    在大规模的缓存应用中,应运而生了分布式缓存系统。key-value如何均匀的分散到集群中?最常规的方式莫过于hash取模的方式。比如集群中可用机器适量为N,那么key值为K的的数据请求很简单的应该路由到ha...
    99+
    2024-04-02
  • c++中怎么实现一个哈希慢算法
    c++中怎么实现一个哈希慢算法,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。首先,我定义了一个哈夫曼树结点:class hNode{ public:  friend&...
    99+
    2023-06-03
  • 同一个文件在windows和linux下计算md5哈希不一致的原因及解决方法
    最近项目需要,需要对客户传过来的文件进行MD5校验,在实现的过程中前前后后遇到了若干问题,在这里总结一下。 md5的计算采用openssl实现,具体代码网上很多,这里不再赘述。需要注意的问题 1 读取文件内...
    99+
    2022-06-04
    解决方法 原因 文件
  • PHP如何解决哈希冲突
    今天小编给大家分享一下PHP如何解决哈希冲突的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。链地址法链地址法是最简单而且最常见...
    99+
    2023-07-06
  • java哈希冲突如何解决
    在Java中,哈希冲突可以通过以下几种方式来解决:1. 链地址法(链表法):当发生哈希冲突时,将冲突的元素存储在一个链表中。在查找元...
    99+
    2023-08-25
    java
  • ava如何实现一致性Hash算法
    这篇文章主要介绍了ava如何实现一致性Hash算法的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇ava如何实现一致性Hash算法文章都会有所收获,下面我们一起来看看吧。1. 实现原理将key映射到 2^32 -...
    99+
    2023-07-05
  • Python底层技术揭秘:如何实现哈希算法
    Python底层技术揭秘:如何实现哈希算法,需要具体代码示例摘要:哈希算法是计算机领域中常用的技术之一,用于快速确定数据的唯一标识。Python作为一门高级语言,提供了许多内建的哈希函数,如hash()函数以及各种散列算法的实现。本文将揭示...
    99+
    2023-11-08
    Python 技术 哈希
软考高级职称资格查询
推荐阅读
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作