何为一致性哈希?一致性哈希和哈希有什么区别?一文深入理解一致性哈希

目录

  • 一、前言
  • 二、哈希
    • 2.1、哈希碰撞
    • 2.2、针对哈希碰撞的两种方案
    • 2.3、为什么用哈希
    • 2.4、普通哈希的缺点
  • 三、一致性哈希
    • 3.1、实现方式 - 哈希环
    • 3.2、场景复现
    • 3.3、优化版本的哈希环
  • 四、总结

一、前言

在学到分布式负载均衡时,负载均衡的方式有很多种,其中一致性哈希与哈希的区别?开一篇文章记录一下一致性哈希的原理。

二、哈希

对于哈希,日常开发中在很多场景都会用到,比如:

  1. md5 之类的哈希函数
  2. 分库、分表时,使用某个字段的 hash 值对固定数值取模,来确定对应库表
  3. 一个大量数据的集合,根据某个字段作为拆分键,对数据进行打散处理
  4. PHP的 HashTable、Go的 map、Python 的 dict 等数据结构实现
  5. Redis 分片时使用 crc16 对key进行哈希,然后对 16384 取模来确定分片
  6. 等等 …
    除上面场景,还有很多地方会用到 hash,而他们都是哈希的一种实现方式。

哈希与一致性哈希

在这里插入图片描述

2.1、哈希碰撞

无限个原始数据在经过Hash函数运算之后,得到的哈希结果会有一定的概率相同。那么,这些不同的原始数据得到相同哈希值的情况,就是哈希碰撞。

例如下图所示:c、d在经过某个哈希函数计算之后得到相同的哈希值10,那么c、d 就发生了哈希碰撞。

在这里插入图片描述

需要了解的:

哈希碰撞无法避免 (因为哈希结果值域是有限的,原始数据是无限的)

哈希值域越大,碰撞概率一般越低

好的哈希函数除了运算速度外,还需要尽量小的哈希碰撞概率

2.2、针对哈希碰撞的两种方案

在出现哈希碰撞情况下常用的方案有:

  1. 开放地址法
  2. 拉链法

开放地址法一般不常使用,读者可以自行查阅相关资料。

拉链法则在很多场景、甚至开源系统都会用到。

例如:PHP的 HashTable(PHP5使用双向链表、PHP7使用数组)、以及Go的map底层实现。

在这里插入图片描述
如图所示,c、d的哈希结果都为10,在存储的时候使用尾插法来把他们串在一起(就像拉了一条锁链一样)。

其中,bucket 为在某一时刻大小固定的数组,下标为哈希值对固定数值取模之后得到。bucket 的大小一般会在某种临界状态下进行自动的扩容、缩容。

查找的时候,根据计算的哈希值先定位到bucket对应位置,然后再遍历链表查找对应数据。

注意:

原始数据经过Hash计算一般会得到比较大的哈希值,此时需用哈希值对bucket大小取模来确定数据存储位置

理想情况下,不会有哈希碰撞,数值落在bucket的不同位置,查找时间复杂度为 O(1)

糟糕情况下,数据全部哈希碰撞,数值都落在bucket同一个位置,查找时间复杂度为 O(n)

2.3、为什么用哈希

例如一个项目,每天数据量2亿多条,这些数据需要落盘。建表的话,如果存在一张表里面,那将会是一个灾难。如果建10张表,使用用户uid对10取模来确定当前数据落在哪一张表里面。

在这里插入图片描述
其中,uid%10 相当于hash算法,这样的话就把2亿多条的数量分拆在不同的表里面,减少了单表数据量,好处的话:可以提升查询速度、数据在同步时效率提升等等。

在这种情况之下,使用哈希对大量数据进行拆分再合适不过了。

2.4、普通哈希的缺点

优点说了一堆,那么接下来说一下不好的地方。

假设有这样一种场景:原来使用了10张表存储数据,完全没有问题。突然有一天,业务要求现在使用20张表或者5张表存储数据,那该怎么办?

由于表的个数发生变化,此时的hash函数 uid%10 就应该变为 uid%20 或者 uid%5。

此时老的数据就需要进行处理,怎么办?rehash!

对全量数据进行rehash,使用新的hash函数重新计算所有数据,再把这些数据存储在新的表中。

实际开发中出现 rehash 的场景会非常多,所以就需要提前做一些预案。

如果数据量非常大的话,一般有两种方案:

停服维护,在维护期间进行数据 rehash 迁移
异步迁移,写数据的时候,使用新的哈希函数确认落在哪一张表里面。查询的时候,如果发现数据没有迁移完成,则需要同时使用多个hash函数,从多张表中读取数据(假设还牵扯分页,则会更加麻烦)。在提供服务的同时,对老数据进行rehash迁移。
方案1需要停服,这就要看产品、公司业务是否允许。允许的情况之下,是最优方案。

方案2不停服进行迁移,相当于边开飞机边换轮胎。风险高、逻辑处理复杂。

还有就是,对于数据量大的情况之下,rehash可能会是个漫长的过程

那么,有没有其他好的解决办法呢?

办法是有,解决问题的角度从迁移全量数据变成了迁移部分数据。它就是:一致性哈希。

三、一致性哈希

维基百科告诉我们:

一致哈希 是一种特殊的哈希算法。在使用一致哈希算法后,哈希表槽位数(大小)的改变平均只需要对K/n 个关键字重新映射,其中 K是关键字的数量,n是槽位数量。然而在传统的哈希表中,添加或删除一个槽位的几乎需要对所有关键字进行重新映射。

一致哈希由MIT的Karger及其合作者提出,现在这一思想已经扩展到其它领域。在这篇1997年发表的学术论文中介绍了“一致哈希”如何应用于用户易变的分布式Web服务中。哈希表中的每一个代表分布式系统中一个节点,在系统添加或删除节点只需要移动 K/n项。

一致哈希也可用于实现健壮缓存来减少大型Web应用中系统部分失效带来的负面影响。

一致哈希的概念还被应用于分布式散列表(DHT)的设计。DHT使用一致哈希来划分分布式系统的节点。所有关键字都可以通过一个连接所有节点的覆盖网络高效地定位到某个节点。

David Karger及其合作者列出了使得一致哈希在互联网分布式缓存中非常有用的几个特性:

  • 冗余少
  • 负载均衡
  • 过渡平滑
  • 存储均衡
  • 关键词单调

3.1、实现方式 - 哈希环

一致哈希将每个对象映射到圆环边上的一个点,系统再将可用的节点机器映射到圆环的不同位置。查找某个对象对应的机器时,需要用一致哈希算法计算得到对象对应圆环边上位置,沿着圆环边上查找直到遇到某个节点机器,这台机器即为对象应该保存的位置。

当删除一台节点机器时,这台机器上保存的所有对象都要移动到下一台机器。

添加一台机器到圆环边上某个点时,这个点的下一台机器需要将这个节点前对应的对象移动到新机器上。

更改对象在节点机器上的分布可以通过调整节点机器的位置来实现。

假设有一个环形结构,上面有很多节点,一般为 2的32次方。(这个值是约定俗成的经验之举)

哈希环

我们需要做的事情大致如下:

对不同节点服务器的某些参数(mac地址、IP地址等)进行hash计算,用hash值对2^32取模,确定当前服务器落在环某一个节点上

数据存储时,对指定的key进行hash计算,然后用hash值对2^32取模,确定数据落在环的哪一个节点上,得到环的节点值之后,顺时针方向找到遇到的第一台服务器,这台服务器就是存储当前数据的地方。

普通哈希环
从图中可以看到,有三台服务器分别落在哈希环的不同节点位置。数据A、B、C、D、E也落在环的不同位置。根据一致性哈希要求,数据在计算得到自己的环中节点之后,顺时针找到第一个服务器节点,那台服务器就是数据的存储位置。

那样的话,可知:

  • 数据D、E、A存储在服务器1
  • 数据B、C存储在服务器2
  • 没有数据存储在服务器3

3.2、场景复现

场景1(缩容)

假设,服务器2发生故障,存在上面的数据都需要迁移

那么,此时只需要迁移服务器1与服务器2之间的数据B、C到服务器3即可。

场景2(扩容)

假设,在数据B、C之间添加服务器4,那么只需要迁移存储在服务器2上的数据B到服务器4即可。

通过上面两个场景可以看出,无论是扩容还是缩容,相对于传统的hash方式,在发生扩、缩容时,只需要迁移一部分数据。大大简化了数据的迁移量,也会大大降低发生问题的概率。

3.3、优化版本的哈希环

通过上面例子可以看出:

数据D、E、A存储在服务器1

数据B、C存储在服务器2

没有数据存储在服务器3

不知道你发现没有:服务器3没有存储数据,服务器1却存储最多的数据,此时就发生了数据倾斜。

那么,有什么办法来解决数据倾斜吗?

办法就是需要对负载策略进行优化,引入虚拟服务器节点。

原来的一台服务器,在哈希环上只能拥有一个节点。那么,此时我们对每一台服务器进行虚拟。例如:原来的服务器1,现在虚拟为2台,服务器1-A、服务器1-B,此时这2台虚拟服务器会在哈希环上拥有不同的2个节点(但是它们实际映射到同一台真实的服务器上)。此时,哈希环就发生了变化。

具有虚拟节点的哈希环
此时,服务器节点由原来的3个节点变为了6个节点。

根据一致性哈希要求,数据存储的位置变为:

  • 数据A存储在服务器1-A
  • 数据B存储在服务器3-A
  • 数据C存储在服务器2-A
  • 数据D存储在服务器1-B
  • 数据E存储在服务器2-B

由于,上面的服务器节点为虚拟服务器节点,最终数据存储在的真实位置:

  • 数据A、D存储在服务器1
  • 数据C、E存储在服务器2
  • 数据 B 存储在服务器3

由此可见,通过引入服务器虚拟节点,数据的存储变得比较均衡。

四、总结

通过一系列的场景分析,我们认识了哈希、哈希碰撞、哈希碰撞的解决办法,并抛出了普通哈希存在的数据全量迁移问题。

同时,也找到了解决全量数据迁移的办法——一致性哈希,通过对一致性哈希的认识,了解到它所拥有的巨大潜力。但是,面对大数据量存储的场景,可能会出现数据倾斜,造成某些服务器的高负载。在引入了服务器虚拟节点之后,对一致性哈希的负载进行了优化,从而达到了一种各个服务器均衡的状态。

实际场景中,面对不同的业务或许会有些许差异。但是,大致逻辑类似。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/537141.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

*地宫取宝c++

题目 输入样例1: 2 2 2 1 2 2 1输出样例1: 2输入样例2: 2 3 2 1 2 3 2 1 5输出样例2: 14 思路 题目说从入口开始,只能向右或向下行走到达右下角,类似“摘花生”这道题的模型。题目又说只有当格子里的宝…

数据结构知识点总结00-知识点目录

专栏主页: 数据结构算法程序设计基础C语言知识点总结https://blog.csdn.net/seeker1994/category_12585732.html C语言知识点总结00-C语言知识点目录 最优算法100例00-最优算法100例目录 ...... 数据结构知识点目录 要求: (1&#xff…

Devin,第一位AI软件工程师

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

微信小程序上传图片到服务端,springboot项目。避免踩坑保姆教程

多方查找终于搞懂了如何去上传文件到本地服务器 前端代码 <view class"operation_row common_mb0"><view class"upload_btn" bindtap"clickUpload"><image src"../../common/images/icon/icon02.png"></image&g…

跨境电商怎么使用动态住宅代理IP?

在数字化时代&#xff0c;隐私保护和信息安全成为全球网民的共同关切。特别是对于海外用户&#xff0c;由于地理位置和网络监管政策的不同&#xff0c;访问全球信息资源变得更加复杂。使用动态住宅IP搭建代理&#xff0c;作为解决这一问题的有效手段&#xff0c;动态IP代理通过…

qiankun:vite/webpack项目配置

相关博文&#xff1a; https://juejin.cn/post/7216536069285429285?searchId202403091501088BACFF113F980BA3B5F3 https://www.bilibili.com/video/BV12T411q7dq/?spm_id_from333.337.search-card.all.click qiankun结构&#xff1a; 主应用base&#xff1a;vue3historyv…

Vue3基础速成

Vue常用语法 {{ }} 变量、表达式渲染 {{ }} 用于输出对象属性和函数返回值 <div id"hello-vue" class"demo">{{ message }} </div><script>const HelloVueApp {data() {return {message: Hello Vue!!}}}Vue.createApp(HelloVueApp).…

Pytorch学习 day13(完整的模型训练步骤)

步骤一&#xff1a;定义神经网络结构 注意&#xff1a;由于一次batch_size的大小为64&#xff0c;表示一次放入64张图片&#xff0c;且Flatten()只会对单张图片的全部通道做拉直操作&#xff0c;也就是不会将batch_size合并&#xff0c;但是一张图片有3个通道&#xff0c;在Ma…

【网络安全】 MSF生成木马教程

本文章仅用于信息安全学习&#xff0c;请遵守相关法律法规&#xff0c;严禁用于非法途径。若读者因此作出任何危害网络安全的行为&#xff0c;后果自负&#xff0c;与作者无关。 环境准备&#xff1a; 名称系统IP攻击机Kali Linux10.3.0.231客户端Windows 710.3.0.234 一、生…

设计模式-行为型模式-模版方法模式

模板方法模式&#xff0c;定义一个操作中的算法的骨架&#xff0c;而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。[DP] 模板方法模式是通过把不变行为搬移到超类&#xff0c;去除子类中的重复代码来体现它的优势。 //首…

在Linux/Ubuntu/Debian中使用windows应用程序/软件

Wine 是一个兼容层&#xff0c;允许你在类 Unix 操作系统&#xff08;包括 Ubuntu&#xff09;上运行 Windows 应用程序。 以下是在 Ubuntu 上安装和使用 Wine 的基本步骤&#xff1a; 在 Ubuntu 上安装 Wine&#xff1a; 更新软件包列表&#xff1a; 打开终端并运行以下命令以…

搭建项目后台系统基础架构

任务描述 1、了解搭建民航后端框架 2、使用IDEA创建基于SpringBoot、MyBatis、MySQL、Redis的Java项目 3、以原项目为参照搭建项目所涉及到的各个业务和底层服务 4、以原项目为例&#xff0c;具体介绍各个目录情况并参照创建相关文件夹 1、创建项目后端 BigData-KongGuan …