场景

单个节点的缓存容量达到上限,无法继续单点增加内存,如何解决?

单个节点支撑的QPS达到上限,如何解决?

初步方案

增加N个缓存节点,为了保证缓存数据的均匀,一般情况会采用对key值hash,然后取模的方式,然后根据结果,确认数据落到哪台节点上:如下:

hash(key)%N

很好,这个的确解决了上面的问题,实现了初步的分布式缓存,数据均匀分散到了各个节点上,流量请求也均匀的分散到了各个节点。

但是如果出现以下情况,会带来什么问题?

1、某台服务器突然宕机。缓存服务器从N变为N-1台。

2、缓存容量达到上限或者请求处理达到上限,需要增加缓存服务器,假定增加1台,则缓存服务器从N变为N+1

上面的情况带来的问题:

增加或者删除缓存服务器的时候,意味着大部分的缓存都会失效。这个是比较致命的一点,缓存失效,如果业务为缓存不命中,查询DB的话,会导致一瞬间DB的压力陡增。可能会导致整个服务不可用。

换种描述方式,我们需要解决怎么样的问题?或者需求是怎样的?

增删机器时,希望大部分key依旧在原有的缓存服务器上保持不变。举例来说:key1,key2,key3原先再Cache1机器上,现在增加一台缓存服务器,希望key1,key2,key3依旧在Cache1机器上,而不是在Cache2机器上。

改进方案(一致性Hash)

一致性哈希算法的简单背景介绍 (此段内容来自网络)

一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似。一致性哈希修正了CARP使用的简单哈希算法带来的问题,使得分布式哈希(DHT)可以在P2P环境中真正得到应用。

一致性hash算法提出了在动态变化的Cache环境中,判定哈希算法好坏的四个定义:(来自百度百科

  1. 平衡性(Balance):平衡性是指哈希的结果能够尽可能分布到所有的缓冲中去,这样可以使得所有的缓冲空间都得到利用。很多哈希算法都能够满足这一条件。

  2. 单调性(Monotonicity):单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中,又有新的缓冲加入到系统中。哈希的结果应能够保证原有已分配的内容可以被映射到原有的或者新的缓冲中去,而不会被映射到旧的缓冲集合中的其他缓冲区。

  3. 分散性(Spread):在分布式环境中,终端有可能看不到所有的缓冲,而是只能看到其中的一部分。当终端希望通过哈希过程将内容映射到缓冲上时,由于不同终端所见的缓冲范围有可能不同,从而导致哈希的结果不一致,最终的结果是相同的内容被不同的终端映射到不同的缓冲区中。这种情况显然是应该避免的,因为它导致相同内容被存储到不同缓冲中去,降低了系统存储的效率。分散性的定义就是上述情况发生的严重程度。好的哈希算法应能够尽量避免不一致的情况发生,也就是尽量降低分散性。

  4. 负载(Load):负载问题实际上是从另一个角度看待分散性问题。既然不同的终端可能将相同的内容映射到不同的缓冲区中,那么对于一个特定的缓冲区而言,也可能被不同的用户映射为不同 的内容。与分散性一样,这种情况也是应当避免的,因此好的哈希算法应能够尽量降低缓冲的负荷。

所以通过上面的定义可以看到,简单的hash(key)%N的方式,违背了 单调性 的这个原则。原因如上面提到的,增删机器的时候,原有的缓存大部分会失效,也就违背了单调性的原则。

介绍:

大部分文章都提到环形的hash空间,但是没有讲为什么是环形的。后面我会聊下我的想法。

使用常见的hash算法可以把一个key值哈希到一个具有2^32个桶的空间中。也可以理解成,将key值哈希到 [0, 2^32) 的一个数字空间中。 我们假设这个是个首尾连接的环形空间。如下图:

假设我们现在有key1,key2,key3,key4 4个key值,我们通过一定的hash算法,将其对应到上面的环形hash空间中。

k1=hash(key1);

k2=hash(key2);

k3=hash(key3);

k4=hash(key4);

同样的,假设我们有3台cache服务器,把缓存服务器通过hash算法,加入到上述的环中。一般情况下是根据机器的IP地址或者唯一的计算机别名进行哈希。

c1=hash(cache1);

c2=hash(cache2);

c3=hash(cache3);

接下来就是数据如何存储到cache服务器上了,key值哈希之后的结果顺时针找上述环形hash空间中,距离自己最近的机器节点,然后将数据存储到上面, 如上图所示,k1 存储到 c3 服务器上, k4,k3存储到c1服务器上, k2存储在c2服务器上。用图表示如下:

增删机器的情况

假设cache3服务器宕机,这时候需要从集群中将其摘除。那么,之前存储再c3上的k1,将会顺时针寻找距离它最近的一个节点,也就是c1节点,这样,k1就会存储到c1上了,看一看下下面的图,比较清晰。

摘除c3节点之后,只影响到了原先存储再c3上的k1,而k3、k4、k2都没有受到影响,也就意味着解决了最开始的解决方案(hash(key)%N)中可能带来的雪崩问题。

增加节点原理和删除时差不多~

新增C4节点之后,原先存储到C1的k4,迁移到了C4,分担了C1上的存储压力和流量压力。

几个问题:

1、为什么需要想象成环形?

为了保证节点宕机摘除之后,原先存储在当前节点的key能找到可存储的位置。举个极端的例子,在不是环状hash空间下,刚好缓存的服务器处于0这个位置,那么0之后是没有任何节点信息的,那么当缓存服务器摘除的时候,以前存储在这台机器上的key便找不到顺时针距离它最近的一个节点了。但如果是环形空间,0之后的最近的一个节点信息有可能是2^32-1这个位置,他可以找到0之后的节点。如下图描述可能清晰一点。

2、为什么是2^32个桶空间?

没有搞清楚,个人理解是为了保证足够的灵活性,减少hash带来的key值冲突。也方便后续增删节点。

继续改进

上面的简单的一致性hash的方案在某些情况下但依旧存在问题:一个节点宕机之后,数据需要落到距离他最近的节点上,会导致下个节点的压力突然增大,可能导致雪崩,整个服务挂掉。

如下图所示,

当节点C3摘除之后,之前再C3上的k1就要迁移到C1上,这时候带来了两部分的压力:

1)、之前请求到C3上的流量转嫁到了C1上,会导致C1的流量增加,如果之前C3上存在热点数据,则可能导致C1扛不住压力挂掉。

2)、之前存储到C3上的key值转义到了C1,会导致C1的内容占用量增加,可能存在瓶颈。

当上面两个压力发生的时候,可能导致C1节点也宕机了。那么压力便会传递到C2上,又出现了类似滚雪球的情况,服务压力出现了雪崩,导致整个服务不可用。

如果解决上面的问题?

虚拟节点。歪果人的脑子真好使,想出这么一个牛逼的方式,虚拟节点。

如上描述,一个节点宕机之后可能会引起下个节点的存储及流量压力变大,这一点违背了最开始提到的四个原则中的 平衡性, 节点宕机之后,流量及内存的分配方式打破了原有的平衡。

虚拟节点,从名字可以看出来,这个节点是个虚拟的,每个实际节点对应多个虚拟节点。比较专业的说法如下:

“虚拟节点”( virtual node )是实际节点(机器)在 hash 空间的复制品( replica ),一实际个节点(机器)对应了若干个“虚拟节点”,这个对应个数也成为“复制个数”,“虚拟节点”在 hash 空间中以hash值排列。

依旧用图片来解释,假设存在以下的真实节点和虚拟节点的对应关系。

Visual100—> Real1

Visual101—> Real1

Visual200—> Real2

Visual201—> Real2

Visual300—> Real3

Visual301—> Real3

同样的,hash之后的结果如下:

hash(Visual100)—> V100  —> Real1

hash(Visual101)—> V101  —> Real1

hash(Visual200)—> V200  —> Real2

hash(Visual201)—> V201  —> Real2

hash(Visual300)—> V300  —> Real3

hash(Visual301)—> V301  —> Real3

key值的hash结果如上,这里暂时不写了。

如图解释:

和之前介绍的不添加虚拟节点的类似,主要聊下如果宕机之后的情况。

假设Real1机器宕机,则会发生一下情况。

1、原先存储在虚拟节点V100上的k1数据将迁移到V301上,也就意味着迁移到了Real3机器上。

2、原先存储再虚拟节点V101上的k4数据将迁移到V200上,也就意味着迁移到了Real2机器上。

结果如下图:

这个就解决之前的问题了,某个节点宕机之后,存储及流量压力并没有全部转移到某台机器上,而是分散到了多台节点上。解决了节点宕机可能存在的雪崩问题。

当物理节点多的时候,虚拟节点多,这个的雪崩可能就越小。

PS:只有2个节点的时候,加入虚拟节点没有用。你懂的。

单个节点的缓存容量达到上限 Hash算法一致性相关推荐

  1. c语言实现一致性hash算法,一致性哈希算法(Consistent Hashing)

    应用场景 这里我先描述一个极其简单的业务场景:用4台Cache服务器缓存所有Object. 那么我将如何把一个Object映射至对应的Cache服务器呢?最简单的方法设置缓存规则:object.has ...

  2. 一致性hash算法虚拟节点_Hash算法和一致性Hash算法

    Hash算法 Hash 算法在路由算法应用中,为了保证数据均匀的分布,例如有 3 个桶,分别是 0 号桶, 1 号桶和 2 号桶:现在有 12 个球,怎么样才能让 12 个球平均分布到 3 个桶中呢? ...

  3. 一致性hash算法虚拟节点_一致性Hash算法原理详解

    数据分片 先让我们看一个例子吧: 我们经常会用 Redis 做缓存,把一些数据放在上面,以减少数据的压力. 当数据量少,访问压力不大的时候,通常一台Redis就能搞定,为了高可用,弄个主从也就足够了: ...

  4. 一致性Hash算法与虚拟节点

    缘起 今天我们来说说"一致性Hash"算法,以及虚拟节点. 这并不是一个难理解的概念,希望一篇文章下来,你能完全吃透. 在网站系统发展初期,前辈工程师探索出了数据库这一系统核心组件 ...

  5. MemCache和一致性Hash算法讲解

    文章目录 1 MemCache讲解 1.1 MemCache是什么 1.2 MemCache访问模型 1.3 MemCache写缓存流程 1.4 一致性Hash算法 1.4.1 余数Hash 1.4. ...

  6. HashMap的工作原理(一):Hash算法

    1.什么是Hash Hash也被称为散列.哈希,对应的英文都是Hash.他们的基本原理都是把任意长度的输入,通过Hash算法变成固定长度的输出.这个映射的规则就是对应的Hash算法,而原始数据映射之后 ...

  7. 什么是一致性 Hash 算法

    数据分片 先让我们看一个例子吧 我们经常会用 Redis 做缓存,把一些数据放在上面,以减少数据的压力. 当数据量少,访问压力不大的时候,通常一台Redis就能搞定,为了高可用,弄个主从也就足够了: ...

  8. 分布式一致性hash算法

    写在前面   在学习Redis的集群内容时,看到这么一句话:Redis并没有使用一致性hash算法,而是引入哈希槽的概念.而分布式缓存Memcached则是使用分布式一致性hash算法来实现分布式存储 ...

  9. 10分钟了解一致性hash算法

    应用场景 当我们的数据表超过500万条或更多时,我们就会考虑到采用分库分表:当我们的系统使用了一台缓存服务器还是不能满足的时候,我们会使用多台缓存服务器,那我们如何去访问背后的库表或缓存服务器呢,我们 ...

最新文章

  1. 标准发布丨央行发布《人工智能算法金融应用评价规范》
  2. 历届试题 买不到的数目
  3. 形态数轴的单点多值现象
  4. android Bitmap用法总结
  5. Asp.net常用技巧
  6. boost::kruskal_minimum_spanning_tree用法的测试程序
  7. int 互换 java_Java基础中Int类型变量值互换的几种方法
  8. HTML+CSS+JS实现 ❤️等离子球体ui动画特效❤️
  9. java继承调用先后_「继承顺序」JAVA继承顺序 - seo实验室
  10. 当模型预测控制遇见机器学习
  11. 【报告分享】2020年中国5G经济报告--助力新时代高质量发展.pdf(附下载链接)...
  12. 百度否认退市;微信官方回应「个人影响度报告」;微软公布 C# 9.0 计划 | 极客头条...
  13. vue 监听div滚动事件
  14. linux和emwin的区别,emWin“自带软件GUIBuilder的使用”
  15. FLASH缓动导航制作方法.
  16. word | word一键排版 | word极速排版 | 真正的一键排版
  17. 【安全牛学习笔记】端口扫描
  18. JavaScript导出excel文件,并修改文件样式
  19. 公交APP评测:谁是最好用的公交线路查询软件?
  20. 现代浏览器的模型(一)

热门文章

  1. 【设计模式之美】<Reading Notes>抽象类与接口
  2. 【C++grammar】析构、友元、拷贝构造函数、深浅拷贝
  3. python 示例_带有示例的Python文件关闭属性
  4. 初中文化能学编程吗_网页编程课程来了,确定不来pick一下!!!|科创辅学进行时...
  5. Linux获得命令帮助
  6. 郓城天气预报软件测试,郓城天气预报15天
  7. HDU 5842—— Lweb and String CCPC 网络赛 1011
  8. uva 1451——Average
  9. 深信服C/C++技术一面二面20180924
  10. 【剑指offer】_14 不用加减乘除做加法