在说redis中的哈希(准确来说是一致性哈希)问题之前,先来看一个问题:为什么在分布式集群中一致性哈希会得到大量应用?

在一个分布式系统中,要将数据存储到具体某个节点,或者将来自客户端的请求分配到某个服务器节点做负载均衡,如果采用普通的hash取模算法进行映射,即如key.hashCode()%N,key代表数据的key,N是服务器节点数,使用上能达到预期效果。

但是如果此时要下线一个服务器或者上线一个新的服务器,那么原来的映射将全部失效。如果是做分布式存储,则需要做数据迁移;如果是做分布式缓存,则原来的缓存失效,需要让新增或下线的节点生效就需要做rehash,数据较大会比较消耗时间(其实这点对HashMap了解的,很熟悉这一点,HashMap在动态扩容进行rehash,数据量过大时很消耗时间影响性能)。这时,一致性哈希就派上用场了。

下面通过几个问题逐步介绍redis2.X和redis3.X中的一些特性,来了解一致性哈希在redis中的应用,以及遇到的问题,不同版本是如何解决的。

1. 假如有两台redis服务器,jedis客户端要存入数据到这两台服务器,它如何知道要存入哪台服务器?

这个就是开篇所说一般的做法:哈希取模。
key.hashcode() % nums(key是redis中的key,nums是redis服务器数)最终结果范围:0到nums-1

2. 此时新增一台redis服务器,数据能写入到新增的机器上吗?不能。还是对原有redis服务器数进行取模。

那么如何解决这一问题呢?nums不定义为redis服务器具体数,而是一个比较大的值:2^32,从而映射到一个比较大的空间内,拿key.hashcode*()% 2^32-1来确定存入的服务器。最终会形成一个一致性哈希环,沿着这个环往下找,直至找到。

当然这里key.hashcode*()% 2^32-1只是举个例子,实际生产中我们会采用哈希算法,如MD5、MurMurHash、crc32将数据映射到一个哈希环上。

3. 假如在新增一台redis服务器C前,数据存在节点A。加入C后,客户端在操作的时候,会出现什么问题?

查找数据时,如果通过一致性哈希算法得出数据在C上,但真实数据在A上,客户端在C上查找会找不到数据就会报空指针异常。
这个其实是在redis2.X中的问题,因为redis2.X不支持冬天扩容。这时我们可以考虑找一个合适的时间点如业务峰值低的时候,将环中的所有数据加载出来,灌入到另外一个新增节点后的环中进行处理。

4. redis3.X如何解决redis2.X的上述问题?

通过上面的问题可以得知redis2.X不支持动态加节点,就算成功加入新节点,数据会发生错乱现象,而redis3.X解决了这个问题:

redis集群内置了16384个哈希槽,当需要在集群中插入数据时,先对key使用crc16算法得出一个结果,然后把结果对16384求余数。这样每个key都会对应一个编号在0~16383之间的哈希槽,redis会根据节点数量大致均等的将哈希槽映射到不同节点。

redis集群的每个节点负责一部分哈希槽,这种结构很容易添加或者删除节点,并且无论是添加删除或者修改某一个节点,都不会造成集群不可用的状态。哈希槽的好处在于可以方便的添加或移除节点:

1)当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点就可以了

2)当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点就行了

5. redis3.X的hash碰撞问题

通过hash映射,当某台机器上数据过多支撑不住导致宕机,此时它负责的数据会分配到其他机器,而redis集群服务器配置一般相同,其他机器也扛不住,就会造成雪崩,即便有主备也解决不了,最终可能导致整个集群都会挂掉。下图演示了节点C宕机,C上的数据映射到D上的示例:

这其实就是分布式系统中极其常见的问题,数据倾斜。可以考虑通过如下方式解决:

1)如给大量相似数据即key相同,给key加上随机串,将key打散尽可能随机分配,避免数据倾斜
2)参考redis2.X版本中"虚拟节点"的做法,为每个真实节点引入N个虚拟节点。具体看下文

6. redis2.X是如何解决hash碰撞的问题?redis2.X有一个非常重要的概念:虚拟节点,每个节点都虚拟出160个虚拟节点。数据的存储是沿着环的顺时针方向找一个虚拟节点,每个虚拟节点都会关联到一个真实节点。

图中的A1、A2、B1、B2、C1、C2、D1、D2都是虚拟节点,机器A负载A1、A2的数据,机器B负载B1、B2的数据,机器C负载C1、C2的数据。由于这些虚拟节点数量很多,均匀分布,因此不会造成"雪崩"现象。


关注微信公众号:大数据学习与分享,获取更对技术干货

Redis中的一致性哈希问题的更多相关文章

  1. 26、redis中默认有多少个哈希槽?

    Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余 ...

  2. redis中默认有多少个哈希槽?

    Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余 ...

  3. Redis的一致性哈希算法

    一.节点取余 根据redis的键或者ID,再根据节点数量进行取余. key:value如下 name:1 zhangsna:18:北京 对name:1 进行hash操作,得出来得值是242342345 ...

  4. Redis中的哈希(Hash)

    Redis 哈希(Hash) Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象. Redis 中每个 hash 可以存储 232 - 1 键值 ...

  5. Tornado 自定义session,与一致性哈希 ,基于redis 构建分布式 session框架

    Tornado 自定义session,与一致性哈希 ,基于redis 构建分布式 session import tornado.ioloop import tornado.web from myhas ...

  6. Redis中哈希分布不均匀该怎么办

    前言 Redis 是一个键值对数据库,其键是通过哈希进行存储的.整个 Redis 可以认为是一个外层哈希,之所以称为外层哈希,是因为 Redis 内部也提供了一种哈希类型,这个可以称之为内部哈希.当我 ...

  7. 面试官:Redis中哈希数据类型的内部实现方式是什么?

    面试官:Redis中基本的数据类型有哪些? 我:Redis的基本数据类型有:字符串(string).哈希(hash).列表(list).集合(set).有序集合(zset). 面试官:哈希数据类型的内 ...

  8. memcache 的内存管理介绍和 php实现memcache一致性哈希分布式算法

    1 网络IO模型 安装memcached需要先安装libevent Memcached是多线程,非阻塞IO复用的网络模型,分为监听主线程和worker子线程,监听线程监听网络连接,接受请求后,将连接描 ...

  9. Nginx一致性哈希模块的Lua实现

    Nginx一致性哈希模块的Lua重新实现 技术背景: 最近在工作中使用了nginx+redis 的架构,redis在后台做分布式存储,每个redis都存放不同的数据,这些数据都是某门户网站通过Hado ...

随机推荐

  1. Vue.js 学习笔记之三:与服务器的数据交互

    显而易见的,之前的02_toDoList存在着一个很致命的缺陷.那就是它的数据只存在于浏览器端,一但用户关闭或重新载入页面,他之前加入到程序中的数据就会全部丢失,一切又恢复到程序的初始状态.要想解决这 ...

  2. Java知识系统回顾整理01基础05控制流程01if

    一.if if(表达式1){ 表达式2: } 如果表达式1的值是true, 就执行表达式2 public class HelloWorld { public static void main(Stri ...

  3. 对于dijkstra最短路算法的复习

    好久没有看图论了,就从最短路算法开始了. dijkstra算法的本质是贪心.只适用于不含负权的图中.因为出现负权的话,贪心会出错. 一般来说,我们用堆(优先队列)来优化,将它O(n2)的复杂度优化为O ...

  4. JAVA学习线路:day01面向对象(继承、抽象类)

    所有的文档和源代码都开源在GitHub: https://github.com/kun213/DailyCode上了.希望我们可以一起加油,一起学习,一起交流. day01面向对象[继承.抽象类] 今 ...

  5. MYSQL账户是否不允许远程连接。如果无法连接可以尝试以下方法:

    mysql账户是否不允许远程连接.如果无法连接可以尝试以下方法: mysql -u root -p //登录MySQL mysql> GRANT ALL PRIVILEGES ON *.* TO ...

  6. Python数据类型---数值类型

    一.整数(Integer)简称Int,又称整型,由正整数.负整数.0构成,不包括小数,分数. a,b=1,2 #一种赋值方法,此时a=1,b=2 print(a+b) #加法 3 print(a-b) ...

  7. CSS的背景

    CSS的背景 1. 背景颜色background-color div { background-color: 颜色值; } 一般情况下元素背景颜色默认是transparent(透明). 2. 背景图片 ...

  8. 多测师讲解selenium_alert弹框定位_高级讲师肖sir

    from selenium import webdriverfrom time import sleepdrvier=webdriver.Chrome()url=r'F:\dcs\DCS课程安排\se ...

  9. MeteoInfoLab脚本示例:多坐标系

    绘图的时候首先要有坐标系(Axes),可以用axes命令创建,如果没有创建在绘图时会自动创建一个.参数里的position是用来置顶坐标系的图形(figure)中的位置的,通过位置置顶,可以将多个坐标 ...

  10. 实现base64的编码解码,深刻理解base64

    上代码 #include<stdio.h> #include<string.h> #include<stdlib.h> const char padding = ' ...