Redis之哈希分片原理一致性哈希算法与crc16算法
集群分片模式
如果Redis只用复制功能做主从,那么当数据量巨大的情况下,单机情况下可能已经承受不下一份数据,更不用说是主从都要各自保存一份完整的数据。在这种情况下,数据分片是一个非常好的解决办法。
Redis的Cluster正是用于解决该问题。它主要提供两个功能:
- 自动对数据分片,落到各个节点上
- 即使集群部分节点失效或者连接不上,依然可以继续处理命令
对于第二点,它的功能有点类似于Sentienl的故障转移(可以了解下之前Sentinel的文章),在这里不细说。下面详细了解下Redis的槽位分片原理,在此之前,先了解下分布式简单哈希算法和一致性哈希算法,以帮助理解槽位的作用。
简单哈希算法
假设有三台机,数据落在哪台机的算法为
c = Hash(key) % 3
例如key A的哈希值为4,4%3=1,则落在第二台机。Key ABC哈希值为11,11%3=2,则落在第三台机上。
利用这样的算法,假设现在数据量太大了,需要增加一台机器。A原本落在第二台上,现在根据算法4%4=0,落到了第一台机器上了,但是第一台机器上根本没有A的值。这样的算法会导致增加机器或减少机器的时候,引起大量的缓存穿透,造成雪崩。
一致性哈希算法
在1997年,麻省理工学院的Karger等人提出了一致性哈希算法,为的就是解决分布式缓存的问题。
在一致性哈希算法中,整个哈希空间是一个虚拟圆环
假设有四个节点Node A、B、C、D,经过ip地址的哈希计算,它们的位置如下
有4个存储对象Object A、B、C、D,经过对Key的哈希计算后,它们的位置如下
对于各个Object,它所真正的存储位置是按顺时针找到的第一个存储节点。例如Object A顺时针找到的第一个节点是Node A,所以Node A负责存储Object A,Object B存储在Node B。
一致性哈希算法大概如此,那么它的容错性和扩展性如何呢?
假设Node C节点挂掉了,Object C的存储丢失,那么它顺时针找到的最新节点是Node D。也就是说Node C挂掉了,受影响仅仅包括Node B到Node C区间的数据,并且这些数据会转移到Node D进行存储。
同理,假设现在数据量大了,需要增加一台节点Node X。Node X的位置在Node B到Node C直接,那么受到影响的仅仅是Node B到Node X间的数据,它们要重新落到Node X上。
所以一致性哈希算法对于容错性和扩展性有非常好的支持。但一致性哈希算法也有一个严重的问题,就是数据倾斜。
如果在分片的集群中,节点太少,并且分布不均,一致性哈希算法就会出现部分节点数据太多,部分节点数据太少。也就是说无法控制节点存储数据的分配。如下图,大部分数据都在A上了,B的数据比较少。
哈希槽
Redis集群(Cluster)并没有选用上面一致性哈希,而是采用了哈希槽(SLOT)的这种概念。主要的原因就是上面所说的,一致性哈希算法对于数据分布、节点位置的控制并不是很友好。
首先哈希槽其实是两个概念,第一个是哈希算法。Redis Cluster的hash算法不是简单的hash(),而是crc16算法,一种校验算法。
另外一个就是槽位的概念,空间分配的规则。其实哈希槽的本质和一致性哈希算法非常相似,不同点就是对于哈希空间的定义。一致性哈希的空间是一个圆环,节点分布是基于圆环的,无法很好的控制数据分布。而Redis Cluster的槽位空间是自定义分配的,类似于Windows盘分区的概念。这种分区是可以自定义大小,自定义位置的。
Redis Cluster包含了16384个哈希槽,每个Key通过计算后都会落在具体一个槽位上,而这个槽位是属于哪个存储节点的,则由用户自己定义分配。例如机器硬盘小的,可以分配少一点槽位,硬盘大的可以分配多一点。如果节点硬盘都差不多则可以平均分配。所以哈希槽这种概念很好地解决了一致性哈希的弊端。
另外在容错性和扩展性上,表象与一致性哈希一样,都是对受影响的数据进行转移。而哈希槽本质上是对槽位的转移,把故障节点负责的槽位转移到其他正常的节点上。扩展节点也是一样,把其他节点上的槽位转移到新的节点上。
但一定要注意的是,对于槽位的转移和分派,Redis集群是不会自动进行的,而是需要人工配置的。所以Redis集群的高可用是依赖于节点的主从复制与主从间的自动故障转移。
集群搭建
下面以最简单的例子,抛开高可用主从复制级转移的内容,来重点介绍下Redis集群是如何搭建,槽位是如何分配的,以加深对Redis集群原理及概念的理解。
redis.conf配置
先找到redis.conf,启用cluster功能。
cluster-enabled yes默认是关闭的,要启用cluster,让redis成为集群的一部分,需要手动打开才行。
然后配置cluster的配置文件
每一个cluster节点都有一个cluster的配置文件,这个文件主要用于记录节点信息,用程序自动生成和管理,不需要人工干预。唯一要注意的是,如果在同一台机器上运行多个节点,需要修改这个配置为不同的名字。
本次为了方便搭建,所有Redis实例都在同一台机器上,所以修改不同的cluster config名字后,复制三份redis.conf配置,以用于启动三个集群实例(cluster至少要三个主节点才能进行)。
集群关联
> redis-server /usr/local/etc/redis/redis-6379.conf --port 6379 &
> redis-server /usr/local/etc/redis/redis-6380.conf --port 6380 &
> redis-server /usr/local/etc/redis/redis-6381.conf --port 6381 &
&符号的作用是让命令在后台执行,但程序执行的log依然会打印在console中。也可以通过配置redis.conf中deamonize yes,让Redis在后台运行。
连上6379的Redis实例,然后通过cluster nodes查看集群范围。
连上其他实例也是一样,目前6379、6380、6381在各自的集群中,且集群只有它们自己一个。
在6379上,通过cluster meet命令,与6380、6381建立链接。
127.0.0.1:6379> cluster meet 127.0.0.1 6380
127.0.0.1:6379> cluster meet 127.0.0.1 6381

可以看到集群中已经包含了6379、6380、6381三个节点了。登录其他节点查看也是一样的结果。即使6380与6381之间没有直接手动关联,但在集群中,节点一旦发现有未关联的节点,会自动与之握手关联。
槽位分配
通过cluster info命令查看集群的状态
state的状态是fail的,还没启用。看下官方的说明
只有state为ok,节点才能接受请求。如果只要有一个槽位(slot)没有分配,那么这个状态就是fail。而一共需要分配16384槽位才能让集群正常工作。
接下来给6379分配05000的槽位,给6380分配500110000的槽位,给6381分配10001~16383的槽位。
> redis-cli -c -p 6379 cluster addslots {0..5000}
> redis-cli -c -p 6380 cluster addslots {5001..10000}
> redis-cli -c -p 6381 cluster addslots {10001..16383}
再看看cluster info
state已经为ok,16384个槽位都已经分配好了。现在集群已经可以正常工作了。
效果测试
随便登上一个实例,记得加上参数-c,启用集群模式的客户端,否则无法正常运行。
redis-cli -c -p 6380
尝试下set、get操作
可以看到,Redis集群会计算key落在哪个卡槽,然后会把命令转发到负责该卡槽的节点上执行。
利用cluster keyslot命令计算出key是在哪个槽位上,从而得出会跳转到哪个节点上执行。
Redis之哈希分片原理一致性哈希算法与crc16算法的更多相关文章
- 进阶的Redis之哈希分片原理与集群实战
前面介绍了<进阶的Redis之数据持久化RDB与AOF>和<进阶的Redis之Sentinel原理及实战>,这次来了解下Redis的集群功能,以及其中哈希分片原理. 集群分片模 ...
- Memcached 笔记与总结(5)Memcached 的普通哈希分布和一致性哈希分布
普通 Hash 分布算法的 PHP 实现 首先假设有 2 台服务器:127.0.0.1:11211 和 192.168.186.129:11211 当存储的 key 经过对 2 (2 台服务器)取模运 ...
- Redis Cluster 的数据分片机制
上一篇<分布式数据缓存中的一致性哈希算法> 文章中讲述了一致性哈希算法的基本原理和实现,今天就以 Redis Cluster 为例,详细讲解一下分布式数据缓存中的数据分片,上线下线时数据迁 ...
- 用于KV集群的一致性哈希Consistent Hashing机制
KV集群的请求分发 假定N为后台服务节点数,当前台携带关键字key发起请求时,我们通常将key进行hash后采用模运算 hash(key)%N 来将请求分发到不同的节点上, 后台节点的增删会引起几乎所 ...
- redis集群与分片(1)-redis服务器集群、客户端分片
下面是来自知乎大神的一段说明,个人觉得非常清晰,就收藏了. 为什么集群? 通常,为了提高网站响应速度,总是把热点数据保存在内存中而不是直接从后端数据库中读取.Redis是一个很好的Cache工具.大型 ...
- 一致性哈希(consistent hashing)算法
文章同步发表在博主的网站朗度云,传输门:http://www.wolfbe.com/detail/201608/341.html 1.背景 我们都知道memcached服务器是不提供分布 ...
- Memcached 笔记与总结(8)Memcached 的普通哈希分布算法和一致性哈希分布算法命中率对比
准备工作: ① 配置文件 config.php ② 封装 Memcached 类 hash.class.php,包含普通哈希算法(取模)和一致性哈希算法 ③ 初始化 Memcached 节点信息 in ...
- redis集群之分片集群的原理和常用代理环境部署
上篇文章刚刚介绍完redis的主从复制集群,但主从复制集群主要是为了解决redis集群的单点故障问题,通过整合哨兵能实现集群的高可用:但是却无法解决数据容量以及单节点的压力问题,所以本文继续介绍red ...
- 一致性哈希算法原理及Java实现
一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致性哈希修正了CARP使用的简 单 ...
- 深入一致性哈希(Consistent Hashing)算法原理,并附100行代码实现
转自:https://my.oschina.net/yaohonv/blog/1610096 本文为实现分布式任务调度系统中用到的一些关键技术点分享——Consistent Hashing算法原理和J ...
随机推荐
- 【JS 逆向百例】百度翻译接口参数逆向
逆向目标 目标:百度翻译接口参数 主页:https://fanyi.youdao.com/ 接口:https://fanyi.baidu.com/v2transapi 逆向参数: Form Data: ...
- @RequestBody中使用@DateTimeFormat报错:JSON parse error: Expected array or string.; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException
原因分析 根据异常提示:不匹配输入异常,指输入的参数错误,说是只支持String类型和Array数组类型的. @PostMapping("/test") public Dto ge ...
- 3.2 IDAPro脚本IDC常用函数
IDA Pro内置的IDC脚本语言是一种灵活的.C语言风格的脚本语言,旨在帮助逆向工程师更轻松地进行反汇编和静态分析.IDC脚本语言支持变量.表达式.循环.分支.函数等C语言中的常见语法结构,并且还提 ...
- x64dbg 实现插件Socket反向通信
编写一个带有socket通信功能的插件,x64dbg运行后,用户点击链接按钮可直接连接到外部的python中,python作为服务端,当x64dbg内部出现某个事件后,自动将消息推送到外部python ...
- MySQL创建, 修改,删除用户密码
MySQL创建, 修改,删除用户密码 创建用新户名密码 创建用新户名密码: create user 'test1'@'localhost' identified by 'test1'; 修改用户名密码 ...
- Netty-介绍-1
Netty介绍和应用场景 要求 已经掌握了 主要技术构成: Java OOP 编程. Java 多线程编程. Java IO 编程 . Java 网络编程. 常用的Java 设计模式(比如 观察者模式 ...
- 零基础入门学习Java之注解与反射
Java反射 Java的程序为什么能在JVM虚拟机中跑起来?接下来将深入探讨下Java虚拟机类加载的机制 1.类的加载 整个Java内存可以分为三大板块 堆 存放new的数组.对象等 栈 存基本变量类 ...
- 零基础入门学习Java课堂笔记 ——day01
Java语法 1.注释.标识符.关键字 注释 不会被程序执行的代码或者块 //双斜杠表示单行注释 /*表示多行注释*/ 标识符.关键字 关键词系统事先定义好的,我们能直接拿来用的,不能作为变量名使用 ...
- Winows11-hosts文件无法修改保存
Win11系统hosts文件无法修改保存 新近使用win11新电脑修改hosts,添加IP和主机名映射,保存时提示host无法修改. 解决办法: 1.将hosts文件的权限"只读" ...
- MySQL8.0-CTE递归查询(避免死循环)
TSQL脚本能实现递归查询,用户使用共用表表达式 CTE(Common Table Expression),只需要编写少量的代码,就能实现递归查询. 本文详细介绍CTE递归调用的特性和使用示例,递归查 ...