Redis 集群(cluster)
Redis 集群是一个提供在多个Redis间节点间共享数据的程序集。
Redis集群并不支持处理多个keys的命令,因为这需要在不同的节点间移动数据,从而达不到像Redis那样的性能,在高负载的情况下可能会导致不可预料的错误.
Redis 集群通过分区来提供一定程度的可用性,在实际环境中当某个节点宕机或者不可达的情况下继续处理命令. Redis 集群的优势:
- 自动分割数据到不同的节点上。
- 整个集群的部分节点失败或者不可达的情况下能够继续处理命令。
数据分布概论
先上一个图直观理解一下数据分区

分区规则包括:顺序分布和哈希分布

两种分布方式:
| 分布方式 | 特点 | 典型产品 |
|---|---|---|
| 哈希分布 | 数据分散度高 键值分布业务无关 无法顺序访问 支持批量操作 |
一致性哈希Memcache redis Cluster 其他缓存产品 |
| 顺序分布 | 数据分散度易倾斜 键值业务相关 可顺序访问 支持批量操作 |
BigTable HBase |
下面主要介绍一些hash分区的具体规则:
Hash分区
节点取余分区
按照 数据节点数mod分区数 进行分区操作:

缺点:数据迁移时不容易操作,迁移量比较大,可通过多倍扩容降低迁移量。
一致性分布哈希算法
具体设计:
1.环形hash空间
按照常用的hash算法来将对应的key哈希到一个具有$$2^{32}$$次方个节点的空间中,即$$ 0 \sim (2^{32})-1$$的数字空间中。现在我们可以将这些数字头尾相连,想象成一个闭合的环形。(节点的个数可以自定义,整个hash环我们可以用TreeMap来实现,因为treeMap是排序的,我们刚好可以利用上)

2.映射服务器节点
将各个服务器使用Hash进行一个哈希,具体可以选择服务器的ip或唯一主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置。假设我们将四台服务器使用ip地址哈希后在环空间的位置如下:

3.映射数据
现在我们将objectA、objectB、objectC、objectD四个对象通过特定的Hash函数计算出对应的key值,然后散列到Hash环上,然后从数据所在位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器。

4.扩容服务器的删除与添加
删除:如果此时NodeC宕机了,此时Object A、B、D不会受到影响,只有Object C会重新分配到Node D上面去,而其他数据对象不会发生变化
添加:如果在环境中新增一台服务器Node X,通过hash算法将Node X映射到环中,通过按顺时针迁移的规则,那么Object C被迁移到了Node X中,其它对象还保持这原有的存储位置。通过对节点的添加和删除的分析,一致性哈希算法在保持了单调性的同时,还是数据的迁移达到了最小,这样的算法对分布式集群来说是非常合适的,避免了大量数据迁移,减小了服务器的的压力。

这种方式相比节点取余最大的好处在于加入和删除节点只影响哈希环中相邻的节点,对其他节点无影响。
但一致性哈希分区存在问题:
1.当服务器节点比较少的时候,会出现一个问题,就是此时必然造成大量数据集中到一个节点上面,极少数数据集中到另外的节点上面。

为了解决这种数据倾斜问题,一致性哈希算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。具体做法可以先确定每个物理节点关联的虚拟节点数量,然后在ip或者主机名后面增加编号。例如上面的情况,可以为每台服务器计算三个虚拟节点,于是可以分别计算 “Node A#1”、“Node A#2”、“Node A#3”、“Node B#1”、“Node B#2”、“Node B#3”的哈希值,于是形成六个虚拟节点:

同时数据定位算法不变,只是多了一步虚拟节点到实际节点的映射,例如定位到“Node A#1”、“Node A#2”、“Node A#3”三个虚拟节点的数据均定位到Node A上。这样就解决了服务节点少时数据倾斜的问题。每个物理节点关联的虚拟节点数量就根据具体的生产环境情况在确定。
2.因为redis是一个高速的存储服务器 , 即使使用一致性hash在扩容的时候还是会导致一个节点的部分时间不可用
所以采用虚拟节点要增加或者减少服务器的时候就可以可以将原来的虚拟节点变成一个真的节点, 将原来由这个虚拟节点映射过来的数据直接复制到新节点上, 就省去了rehash的操作
虚拟槽分区(redis cluster使用)
- 正因为一致性哈希分区的这些缺点,一些分布式系统(redis cluster)采用虚拟槽对一致性哈希进行改造
- 其实本质上虚拟槽中的槽就是大量的虚拟节点的抽象化, 将原来的虚拟节点变成一个槽, redis内置是有16383个槽也就是有16383个虚拟节点
- 虚拟槽分区巧妙地使用了哈希空间,使用分散度良好的哈希函数把所有数据映射到一个固定范围的整数集合中,整数定义为槽(slot)。这个范围 一般远远大于节点数,比如Redis Cluster槽范围是0~16383
- 如下图所示:当前集群有5个节点,每个节点平均大约负责3276个槽

- 由于采用高质量的哈希算法,每个槽所映射的数据通常比较均匀,将数据平均划分到5个节点进行数据分区, 所以redis使用的就是虚拟槽分区
- 采用虚拟槽分区,所有的键根据哈希函数映射到0~16383整数槽内,计算公式:slot=CRC16(key)&16383。每一个节点负责维护一部分槽以及槽所映射的键值数据,如下图所示

Redis虚拟槽分区的特点:
1.解耦数据和节点之间直接关系, 一致性hash计算方式是key & 节点个数, 映射的结果和节点个数有关系, 但是使用hash槽计算方式是 CRC16(key) % 槽的个数, 所以就解耦了数据和节点的关系。
2.使用哈希槽的好处就在于可以方便的添加或移除节点。
- 当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点就可以了;
- 当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点就行了;
- 在这一点上,我们以后新增或移除节点的时候不用先停掉所有的 redis 服务甚至不用停到任何一个节点的服务。对应槽的采用直接复制数据过去显然比rehash快很多。
3.节点自身维护槽的映射关系, 不需要客户端和代理服务器进行维护处理
Redis 集群模式
1.主从模式,单台服务器即可,无高可用,为1主2从方式
主节点可读写,从节点只读,数据会从主节点同步至从节点
2.cluster模式 3.0以上版本支持
分布式特性
分布式特性:服务端每个节点相互通信,且每个节点负责读写。

redis cluster架构
Redis Cluster 基本架构:Redis Cluster 中有多个主节点,每个主节点都负责进行数据读写操作,并且每个节点之间会进行通信。
redis cluster是一个去中心化的集群,每个节点都会跟其他节点保持连接,每个节点之间会互相通信。以下是一些基本概念。
- 节点:基本节点,完成读写数据
- meet:完成每个节点相互通信的操作
- 指派槽:给启动的节点指派槽。当节点收到访问请求时,会根据key来判断要访问的数据是否在槽内。
- 复制:每个主节点都有一个从节点。节点之间相互交互。
要保证高可用,每个主节点都至少有一个从节点,当主节点故障,Cluster 会按照规则实现主备的高可用性,对于节点来说,有一个配置项:cluster-enabled,即是否以集群模式启动。
Redis Cluster 部署
方式一:原生命令
1.配置开启节点
2.meet
3.指派槽
4.主从
Redis cluster 节点主要配置
cluster-enabled yes # 表示当前节点为cluster节点
cluster-node-timeout 15000 # 故障转移时间,节点超时时间,主观下线时间
cluster-config-file "nodes-${port}.conf" # 集群配置文件(节点配置)
cluster-require-full-coverage yes # 是否需要集群内所有节点都可以提供服务
开启节点
redis-server redis-7000.conf # 开启端口7000的节点
redis-server redis-7001.conf # 开启端口7001的节点
redis-server redis-7002.conf # 开启端口7002的节点
redis-server redis-7003.conf # 开启端口7003的节点
redis-server redis-7004.conf # 开启端口7004的节点
redis-server redis-7005.conf # 开启端口7005的节点
meet实现节点之间的相互通信
redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7001
redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7002
redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7003
redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7004
redis-cli -h 127.0.0.1 -p 7000 cluster meet 127.0.0.1 7005
此时,所有节点彼此之间都可以相互感知
分配槽(0~16383)
redis-cli -h 127.0.0.1 -p 7000 cluster addslots [0...5461] # 这里最好用shell实现
redis-cli -h 127.0.0.1 -p 7001 cluster addslots [5462...10922]
redis-cli -h 127.0.0.1 -p 7002 cluster addslots [10923...16383]
设置主从(一主一从)
# 主 7000 从 7003
redis-cli -h 127.0.0.1 -p 7003 cluster replicate ${node-id-7000}
# 主 7001 从 7004
redis-cli -h 127.0.0.1 -p 7004 cluster replicate ${node-id-7001}
# 主 7002 从 7005
redis-cli -h 127.0.0.1 -p 7005 cluster replicate ${node-id-7002}
方式二:Ruby环境
下载ruby环境,参考网上教程