redis cluster集群——高可用 (哈希槽)

1.概述

redis的主从和哨兵两种集群方案,redis从3.0版本开始引入了redis-cluster(集群)。
从主从-哨兵-集群可以看到redis的不断完善;主从复制是最简单的节点同步方案无法主从自动故障转移。
哨兵可以同时管理多个主从同步方案同时也可以处理主从自动故障转移,通过配置多个哨兵节点可以解决单点网络故障问题,
但是单个节点的性能压力问题无法解决。集群解决了前面两个方案的所有问题。

(1)Redis-Cluster采用无中心结构
每个节点都和其它节点通过互ping保持连接,每个节点保存整个集群的状态信息,可以通过连接任意节点读取或者写入数据
(甚至是没有数据的空节点)。

(2)只有当集群中的大多数节点同时fail整个集群才fail
一般情况下是集群当中超过一半以上的节点fail的时候,集群才会fail

(3)整个集群有16384个slot
当需要在 Redis 集群中放置一个key-value 时,根据 CRC16(key) mod 16384的值,决定将一个key放到哪个桶中。
读取一个key时也是相同的算法。

(4)当主节点fail时从节点会升级为主节点
fail的主节点online之后自动变成了从节点
redis cluster集群——高可用 (哈希槽)
Redis集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对key 使用 crc16 算法算出一个结果,
然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,
redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。

2.什么是哈希槽?

Redis 集群没有使用一致性hash, 而是引入了哈希槽的概念。
Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽。
这种结构很容易添加或者删除节点,并且无论是添加删除或者修改某一个节点,都不会造成集群不可用的状态。
使用哈希槽的好处就在于可以方便的添加或移除节点。
当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点就可以了;
当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点就行了;
在这一点上,我们以后新增或移除节点的时候不用先停掉所有的 redis 服务。

当你往Redis Cluster中加入一个Key时,会根据crc16(key) mod 16384计算这个key应该分布到哪个hash slot中,
一个hash slot中会有很多key和value。你可以理解成表的分区,使用单节点时的redis时只有一个表,所有的key都放在这个表里;
改用Redis Cluster以后会自动为你生成16384个分区表,你insert数据时会根据上面的简单算法来决定你的key应该存在哪个分区
关系:cluster>node>slot>key

数据迁移
数据迁移可以理解为slot(槽)和key的迁移,这个功能很重要,极大地方便了集群做线性扩展,以及实现平滑的扩容或缩容。
现在要将Master A节点中编号为1、2、3的slot迁移到Master B节点中,
在slot迁移的中间状态下,slot 1、2、3在Master A节点的状态表现为MIGRATING(迁移),
在Master B节点的状态表现为IMPORTING(入口)。
redis cluster集群——高可用 (哈希槽)
此时并不刷新node的映射关系
IMPORTING状态
被迁移slot 在目标Master B节点中出现的一种状态,
准备迁移slot从Mater A到Master B的时候,被迁移slot的状态首先变为IMPORTING状态。

复制&高可用:
集群的节点内置了复制和高可用特性。
特点:
1、节点自动发现
2、slave->master 选举,集群容错
3、Hot resharding:在线分片
4、基于配置(nodes-port.conf)的集群管理
5、客户端与redis节点直连、不需要中间proxy层.
6、所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.

4.高可用redis cluster集群的具体实现过程如下:
(1)在server1(master)上面进行设置
overcommit_memory是什么?
overcommit_memory是一个内核对内存分配的一种策略。 具体可见/proc/sys/vm/overcommit_memory下的值
overcommit_memory有什么作用?
overcommit_memory取值又三种分别为0, 1, 2
overcommit_memory=0, 表示内核将检查是否有足够的可用内存供应用进程使用;
如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。
overcommit_memory=1, 表示内核允许分配所有的物理内存,而不管当前的内存状态如何。
overcommit_memory=2, 表示内核允许分配超过所有物理内存和交换空间总和的内存
redis cluster集群——高可用 (哈希槽)
在这里将值设置为1
redis cluster集群——高可用 (哈希槽)
(2)在server1上创建 6个Redis 节点
首先在 server1 机器上 /usr/local/目录下创建 redis_cluster 目录;
在 redis_cluster 目录下,创建名为7001、7002、7003、7004、7005、7006的目录
进入7001目录,编写redis.conf文件
redis cluster集群——高可用 (哈希槽)
port 7001 //端口7001,7002,7003,7004,7005,7006
cluster-enabled yes //开启集群
cluster-config-file nodes.conf //集群的配置,配置文件首次启动自动生成 7001,7002,7003,7004,7005,7006
cluster-node-timeout 15000 //请求超时 默认15秒,可自行设置
appendonly yes //aof日志开启 有需要就开启,它会每次写操作都记录一条日志
daemonize yes //后台运行

redis cluster集群——高可用 (哈希槽)
重启服务,查看进程
redis cluster集群——高可用 (哈希槽)
同理配置其他5个节点,并且开启服务
redis cluster集群——高可用 (哈希槽)
最终可以查看6个节点全部开启
redis cluster集群——高可用 (哈希槽)
(3)在server1上创建redis-cluster集群
注意:要指定一主一从
redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 --cluster-replicas 1
redis cluster集群——高可用 (哈希槽)
redis cluster集群——高可用 (哈希槽)
可以看出7001,2,3是master,7004,5,6是slave

测试:集群中三个master,三个slave,数据完全同步
三个master分别为:server1、server2、server3

server1的slave是server5
redis cluster集群——高可用 (哈希槽)
redis cluster集群——高可用 (哈希槽)
server2的slave是server6
redis cluster集群——高可用 (哈希槽)
redis cluster集群——高可用 (哈希槽)
server3的slave是server4
redis cluster集群——高可用 (哈希槽)
redis cluster集群——高可用 (哈希槽)
检查各个redis节点的运行情况,6个节点都可以查看
redis cluster集群——高可用 (哈希槽)
(4)接下来测试集群的高可用
DOWN掉7002后发现,进程中没有7002了,redis-cli --cluster check 127.0.0.1:7001发现7006变成了master
redis cluster集群——高可用 (哈希槽)
节点7002已经不可用
redis cluster集群——高可用 (哈希槽)
其他5个节点依然可以正常查看数据
redis cluster集群——高可用 (哈希槽)
然后将server6也down掉,再次查看发现只有两个master了
redis cluster集群——高可用 (哈希槽)
检查集群中的哈希槽已经分配不完了,集群已经down了
redis cluster集群——高可用 (哈希槽)
恢复server2和server4节点的服务
redis cluster集群——高可用 (哈希槽)
查看集群状态,发现6个节点都正常
redis cluster集群——高可用 (哈希槽)
然后同时down掉两个master
redis cluster集群——高可用 (哈希槽)
再次检测集群,发现集群已经down掉,哈希槽分配不完了
redis cluster集群——高可用 (哈希槽)
redis cluster集群——高可用 (哈希槽)
当集群当中的一半以上的master都down掉以后,集群也会down掉了

添加新节点到集群中
redis cluster集群——高可用 (哈希槽)
将实例添加到集群中
redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7001 ##默认添加的是master ;7001是给定一个入口
redis cluster集群——高可用 (哈希槽)
检测集群,查看7007是否添加到集群中
redis-cli --cluster check 127.0.0.1:7001
redis cluster集群——高可用 (哈希槽)
发现7007已经是集群中的master现在为7007加入slave7008
redis-cli --cluster add-node --cluster-slave --cluster-master-id “master7007的ID” 127.0.0.1:7008 127.0.0.1:7001
redis cluster集群——高可用 (哈希槽)
redis cluster集群——高可用 (哈希槽)
加入7008slave给7007master成功

但此时master7007上是没有哈希槽的,所以需要给7007分配哈希槽

迁移哈希槽
redis-cli --cluster reshard --cluster-from all --cluster-to d725f58bb3c41a92405fa4d3119bddbf91f06a73 --cluster-slots 300 --cluster-yes 127.0.0.1:7001
–cluster-from all 所有节点 ; --cluster-slots 300 迁移哈希槽个数
redis cluster集群——高可用 (哈希槽)
迁移后查看集群信息,发现已经得到300个哈希槽
redis cluster集群——高可用 (哈希槽)
平均分哈希槽
redis-cli --cluster rebalance --cluster-threshold 1 --cluster-use-empty-masters 127.0.0.1:7001
redis cluster集群——高可用 (哈希槽)
看集群信息,每个master都是4096个哈希槽
redis cluster集群——高可用 (哈希槽)