在说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. 剑指offer-链表&数组

    1.圆圈中最后剩下的数 每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此.HF作为牛客的资深元老,自然也准备了一些小游戏.其中,有个游戏是这样的:首先,让小朋友们围成一个大圈. ...

  2. DORIS系统概述

    DORIS(Doppler Orbitography and Radio-positioning Integrated by Satellite)(多普勒轨道学与无线电定位集成卫星),它是由法国Cne ...

  3. 《穷查理年鉴》金钱 & 生意 & 律师(关于金钱)

    金钱 025.钱还得快才会借得快. 030.钱和人有着复杂的友谊:人能让钱变坏,钱也能让人变坏. 034.绝望增加债务,勤奋偿还债务. 037.只有一无所有的人才会没有烦恼. 049.穷人为他的胃找食 ...

  4. Java基础系列-SPI你认识吗

    原创文章,转载请标注出处:https://www.cnblogs.com/V1haoge/p/10755313.html 一.SPI是什么 SPI是相对API而言的. API指的是应用对服务调用方提供 ...

  5. 35岁的程序员正在消失?No,我认识了一个50岁的程序员!

    35岁的话题真是无穷无尽.一开始的时候,以为只有社交媒体上会有这种问题的讨论,没想到,公司内部的论坛上也有不少这类的文章.大家各有各的说法,但终究也没有找到银弹似的解决方案. 这段时间,倒是接触了一个 ...

  6. 谈谈FTP

    一.关于FTP 1.FTP是什么? FTP,全称"文件传输协议".属于TCP/IP四层模型中的应用层. 2.TCP/IP五层模型有哪些? 如图所示: 用文字叙述(从高层到底层): ...

  7. rabbitmq 交换机模式 -主题模式 topic

    建立一个交换机 tpc 并且绑定了各自的路由到 Q1 Q2 <?php require_once "./vendor/autoload.php"; use PhpAmqpLi ...

  8. python去除特殊字符

    去除数字,特殊字符,只保留汉字 ? 1 2 3 4 5 6 7 8 import re    s = '1123*#$ 中abc国' str = re.sub('[a-zA-Z0-9'!"# ...

  9. scrapy-下载器中间件 随机切换user_agent

    from faker import Faker class MySpiderMiddleware(object): def __init__(self): self.fake = Faker() de ...

  10. Ansible之YAML语言

    playbook写yml语句,若干模块发给Ansible,变成一个一个play,多个片段组合起来变成大片. 最终还是要读取主机清单,来确定作用在哪些机器上. YAML语言 YAML是一个可读性高的用来 ...