
Redis集群是一个提供在多个Redis节点之间共享数据的程序集。它并不像Redis主从复制模式那样只提供一个master节点提供写服务,而是会提供多个master节点提供写服务,每个master节点中存储的数据都不一样,这些数据通过数据分片的方式被自动分割到不同的master节点上。
我们一般要实现一个Redis集群,可以有三种方式:客户端实现、Proxy代理层、服务端实现。
我们通过代码的实现方式,实现集群访问,如下图所示:

这样的访问方式都通过代码来维护集群以及访问路径,可是这样的方式 维护难度大,也不支持动态扩容,因为一切都以代码实现访问规划。
如图所示:

我们在Redis和我们的客户端之间新加了一层Proxy,我们通过Proxy去规划访问,这样我们在代码层面以及Redis部署层面就无需处理,而且市面上也提供了这样的中间件,如Codis(国产)、Twemproxy。我们看下Codis的架构图,就可以知道这个插件是如何工作的,如图所示:

可见Codis是一个很完善的集群管理实现,我们可以不关心具体分片规则,程序开发容易简单,可是这样也有它的一些缺点:
Codis的GitHub地址:https://github.com/CodisLabs/codis
服务端的实现方式就是标准的集群(分区分片)模式,RedisCluster是Redis在3.0版本后推出的分布式解决方案。
Cluster模式实现了Redis的分布式存储,即每台节点存储不同的内容,来解决在线扩容的问题。如图:

RedisCluster采用无中心结构,它的特点如下:
为了保证集群的高可用,每个master节点下面还需要添加至少1个slave节点,这样当某个master节点发生故障后,可以从它的slave节点中选举一个作为新的master节点继续提供服务。不过当某个master节点和它下面所有的slave节点都发生故障时,整个集群就不可用了。这样就组成了下图中的结构模式:

为什么需要三主三从?
因为内部存在一个投票机制,节点的有效性是需要靠投票的,一个节点无法给自己投票,两个节点互相都连不上,A=>B,B=>A互相都说对方挂了没有定论.三个节点才能满足投票的需求。
Cluster模式的具体工作机制:


Cluster模式集群节点最小配置6个节点(3主3从,因为需要半数以上),其中主节点提供读写操作,从节点作为备用节点,不提供请求,只作为故障转移使用。关于集群中的涉及动态选举的机制,请参考地址:Raft
既然Redis集群中的数据是通过哈希槽的方式分开存储的,那么集群中每个节点都需要知道其他所有节点的状态信息,包括当前集群状态、集群中各节点负责的哈希槽、集群中各节点的master-slave状态、集群中各节点的存活状态等。Redis集群中,节点之间通过建立TCP连接,使用gossip协议来传播集群的信息。如下图:

所谓gossip协议,指的是一种消息传播的机制,类似人们传递八卦消息似的,一传十,十传百,直至所有人都知道这条八卦内容。Redis集群中各节点之间传递消息就是基于gossip协议,最终达到所有节点都会知道整个集群完整的信息。gossip协议有4种常用的消息类型:PING、PONG、MEET、FAIL。
Redis客户端可以向Redis集群中的任意master节点发送操作指令,可以向所有节点(包括slave节点)发送查询指令。当Redis节点接收到相关指令时,会先计算key落在哪个哈希槽上(对key进行CRC16校验后再对16384取模),如果key计算出的哈希槽恰好在自己节点上,那么就直接处理指令并返回结果,如果key计算出的哈希槽不在自己节点上,那么当前节点就会查看它内部维护的哈希槽与节点ID之间的映射关系,然后给客户端返回一个MOVED错误:MOVED [哈希槽] [节点IP:端口]。这个错误包含操作的key所属的哈希槽和能处理这个请求的Redis节点的IP和端口号,例如“MOVED 3999 127.0.0.1:6379”,客户端需要根据这个信息重新发送查询指令到给定的IP和端口的Redis节点。

优点:
缺点:
集群内部采用Gossip协议(谣言传播)协同自动化修复集群的状态,但Gossip有消息延时和消息冗余的问题,在集群节点数量过多的时候,节点之间需要不断进行PING/PANG通讯,不必须要的流量占用了大量的网络资源。
Redis Cluster可以进行节点的动态扩容缩容,在扩缩容的时候,就需要进行数据迁移。而Redis 为了保证迁移的一致性, 迁移所有操作都是同步操作,执行迁移时,两端的 Redis 均会进入时长不等的 阻塞状态。对于小 Key,该时间可以忽略不计,但如果一旦 Key 的内存使用过大,严重的时候会接触发集群内的故障转移,造成不必要的切换.
Gossip 的缺陷 - 消息的延迟 由于 Gossip 协议中,节点只会随机向少数几个节点发送消息,消息最终是通过多 个轮次的散播而到达全网的。 因此使用 Gossip 协议会造成不可避免的消息延迟。不适合用在对实时性要求较高 的场景下。
消息冗余 Gossip 协议规定,节点会定期随机选择周围节点发送消息,而收到消息的节点也会重复该步骤。 因此存在消息重复发送给同一节点的情况,造成了消息的冗余,同时也增加了收到消息的节点的处理压力。 而且,由于是定期发送而且不反馈,因此即使节点收到了消息,还是会反复收到重复消息,加重了消息的冗余。
首先我们复制6份redis.conf配置文件,分别命名为redis7001.conf、redis7002.conf、redis7003.conf、redis7004.conf、redis7005.conf、redis7006conf,存放在自己想要放的地方。
并按照下列配置信息修改配置文件:
- #修改成自己对应的端口号
- port
- #指定了记录日志的文件。
- logfile
- #数据目录,数据库的写入会在这个目录。rdb、aof文件也会写在这个目录
- dir
- #是否开启集群
- cluster-enabled
- #集群配置文件的名称,每个节点都有一个集群相关的配置文件,持久化保存集群的信息。
- #这个文件并不需要手动配置,这个配置文件由Redis生成并更新,每个Redis集群节点需要一个单独的配置文件,请确保与实例运行的系统中配置文件名称不冲突(建议配对应端口号)
- cluster-config-file nodes-6379.conf
- #节点互连超时的阀值。集群节点超时毫秒数
- cluster-node-timeout 5000
- #默认redis使用的是rdb方式持久化,这种方式在许多应用中已经足够用了。
- #但是redis如果中途宕机,会导致可能有几分钟的数据丢失,根据save来策略进行持久化,Append Only File是另一种持久化方式,可以提供更好的持久化特性。
- #Redis会把每次写入的数据在接收后都写入 appendonly.aof 文件,每次启动时Redis都会先把这个文件的数据读入内存里,先忽略RDB文件。
- appendonly
- appendonly yes
- protected-mode no #保护模式 yes改为no
- #bind 127.0.0.1 #注释或者去掉这个
- daemonize yes #用来指定redis是否要用守护线程的方式启动,yes表示后台启动
执行命令分别启动所有节点,如:
- /Volumes/work/redis-5.0.8/src/redis-server
- /Volumes/work/redis-5.0.8/conf/7001/redis7001.conf
- /Volumes/work/redis-5.0.8/src/redis-server
- /Volumes/work/redis-5.0.8/conf/7002/redis7002.conf
- /Volumes/work/redis-5.0.8/src/redis-server
- /Volumes/work/redis-5.0.8/conf/7003/redis7003.conf
- /Volumes/work/redis-5.0.8/src/redis-server
- /Volumes/work/redis-5.0.8/conf/7004/redis7004.conf
- /Volumes/work/redis-5.0.8/src/redis-server
- /Volumes/work/redis-5.0.8/conf/7005/redis7005.conf
- /Volumes/work/redis-5.0.8/src/redis-server
- /Volumes/work/redis-5.0.8/conf/7006/redis7006.conf
可以查看到进程:
- 192:conf houjing$ ps -ef |grep redis
- 501 43005 1 0 5:46上午 ?? 0:00.20 /Volumes/work/redis-5.0.8/src/redis-server *:7001 [cluster]
- 501 43018 1 0 5:47上午 ?? 0:00.02 /Volumes/work/redis-5.0.8/src/redis-server *:7002 [cluster]
- 501 43020 1 0 5:47上午 ?? 0:00.02 /Volumes/work/redis-5.0.8/src/redis-server *:7003 [cluster]
- 501 43022 1 0 5:47上午 ?? 0:00.02 /Volumes/work/redis-5.0.8/src/redis-server *:7004 [cluster]
- 501 43024 1 0 5:47上午 ?? 0:00.02 /Volumes/work/redis-5.0.8/src/redis-server *:7005 [cluster]
- 501 43026 1 0 5:47上午 ?? 0:00.01 /Volumes/work/redis-5.0.8/src/redis-server *:7006 [cluster]
执行命令创建集群:
- /Volumes/work/redis-5.0.8/src/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 # 1表示每个主节点至少一个备份
可以得到如下结果:
- 192:conf houjing$ /Volumes/work/redis-5.0.8/src/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
- >>> Performing hash slots allocation on 6 nodes...
- Master[0] -> Slots 0 - 5460
- Master[1] -> Slots 5461 - 10922
- Master[2] -> Slots 10923 - 16383
- Adding replica 127.0.0.1:7005 to 127.0.0.1:7001
- Adding replica 127.0.0.1:7006 to 127.0.0.1:7002
- Adding replica 127.0.0.1:7004 to 127.0.0.1:7003
- >>> Trying to optimize slaves allocation for anti-affinity
- [WARNING] Some slaves are in the same host as their master
- M: 4c7fcd06c55ceec27b5bbc450b99159282e7783e 127.0.0.1:7001
- slots:[0-5460] (5461 slots) master
- M: d7a0d77d2f0fa05ccf4a14e379b52044b212607e 127.0.0.1:7002
- slots:[5461-10922] (5462 slots) master
- M: 6494df31d4ed564d80947c9d39369cc7cfb6c0e6 127.0.0.1:7003
- slots:[10923-16383] (5461 slots) master
- S: 9d6d78888e579442b209fca95af13b6ece4810b6 127.0.0.1:7004
- replicates 6494df31d4ed564d80947c9d39369cc7cfb6c0e6
- S: 8891bfe505da42298be048364ed003b83dc52139 127.0.0.1:7005
- replicates 4c7fcd06c55ceec27b5bbc450b99159282e7783e
- S: 981ad9769245c140c0bd9ee239472dc6e2cb07eb 127.0.0.1:7006
- replicates d7a0d77d2f0fa05ccf4a14e379b52044b212607e
- Can I set the above configuration? (type 'yes' to accept): yes 此处输入yes
- >>> Nodes configuration updated
- >>> Assign a different config epoch to each node
- >>> Sending CLUSTER MEET messages to join the cluster
- Waiting for the cluster to join
- ...
- >>> Performing Cluster Check (using node 127.0.0.1:7001)
- M: 4c7fcd06c55ceec27b5bbc450b99159282e7783e 127.0.0.1:7001
- slots:[0-5460] (5461 slots) master
- 1 additional replica(s)
- S: 981ad9769245c140c0bd9ee239472dc6e2cb07eb 127.0.0.1:7006
- slots: (0 slots) slave
- replicates d7a0d77d2f0fa05ccf4a14e379b52044b212607e
- M: 6494df31d4ed564d80947c9d39369cc7cfb6c0e6 127.0.0.1:7003
- slots:[10923-16383] (5461 slots) master
- 1 additional replica(s)
- S: 9d6d78888e579442b209fca95af13b6ece4810b6 127.0.0.1:7004
- slots: (0 slots) slave
- replicates 6494df31d4ed564d80947c9d39369cc7cfb6c0e6
- M: d7a0d77d2f0fa05ccf4a14e379b52044b212607e 127.0.0.1:7002
- slots:[5461-10922] (5462 slots) master
- 1 additional replica(s)
- S: 8891bfe505da42298be048364ed003b83dc52139 127.0.0.1:7005
- slots: (0 slots) slave
- replicates 4c7fcd06c55ceec27b5bbc450b99159282e7783e
- [OK] All nodes agree about slots configuration.
- >>> Check for open slots...
- >>> Check slots coverage...
- [OK] All 16384 slots covered.
可以执行命令 ./redis-cli -c -p 7001 进行登录,然后查看集群信息以及slot分配信息:
- 192:src houjing$ ./redis-cli -c -p 7001
- 127.0.0.1:7001> cluster nodes
- 981ad9769245c140c0bd9ee239472dc6e2cb07eb 127.0.0.1:7006@17006 slave d7a0d77d2f0fa05ccf4a14e379b52044b212607e 0 1586210070424 6 connected
- 4c7fcd06c55ceec27b5bbc450b99159282e7783e 127.0.0.1:7001@17001 myself,master - 0 1586210069000 1 connected 0-5460
- 6494df31d4ed564d80947c9d39369cc7cfb6c0e6 127.0.0.1:7003@17003 master - 0 1586210071437 3 connected 10923-16383
- 9d6d78888e579442b209fca95af13b6ece4810b6 127.0.0.1:7004@17004 slave 6494df31d4ed564d80947c9d39369cc7cfb6c0e6 0 1586210069416 4 connected
- d7a0d77d2f0fa05ccf4a14e379b52044b212607e 127.0.0.1:7002@17002 master - 0 1586210070000 2 connected 5461-10922
- 8891bfe505da42298be048364ed003b83dc52139 127.0.0.1:7005@17005 slave 4c7fcd06c55ceec27b5bbc450b99159282e7783e 0 1586210070000 5 connected
可以根据以上得出总共有3个master节点,每个节点有一个slave节点,三个master节点分别分配了0-5460、5461-10922、10923-16383三个slot范围,7001这个master节点的slave节点为7005节点,其id为4c7fcd06c55ceec27b5bbc450b99159282e7783e。
添加数据,可以看到数据会根hash然后存到对应的slot槽,也就是存到slot槽对应的节点上,如下所示:
- 127.0.0.1:7001> set 789 789
- -> Redirected to slot [11123] located at 127.0.0.1:7003
- OK
- 127.0.0.1:7003> set 123 123
- -> Redirected to slot [5970] located at 127.0.0.1:7002
- OK
- 127.0.0.1:7002> set 365 365
- -> Redirected to slot [5424] located at 127.0.0.1:7001
- OK
当然每个节点也只有自己的那部分数据:
- 127.0.0.1:7001> keys *
- 1) "365"
我们通过手动杀掉节点7001的进程:
- 192:bin houjing$ kill 43005
- 192:bin houjing$ ps -ef|grep redis
- 501 43018 1 0 5:47上午 ?? 0:03.91 /Volumes/work/redis-5.0.8/src/redis-server *:7002 [cluster]
- 501 43020 1 0 5:47上午 ?? 0:03.94 /Volumes/work/redis-5.0.8/src/redis-server *:7003 [cluster]
- 501 43022 1 0 5:47上午 ?? 0:03.95 /Volumes/work/redis-5.0.8/src/redis-server *:7004 [cluster]
- 501 43024 1 0 5:47上午 ?? 0:03.92 /Volumes/work/redis-5.0.8/src/redis-server *:7005 [cluster]
- 501 43026 1 0 5:47上午 ?? 0:03.91 /Volumes/work/redis-5.0.8/src/redis-server *:7006 [cluster]
然后查看集群信息:
- 127.0.0.1:7002> cluster nodes
- 8891bfe505da42298be048364ed003b83dc52139 127.0.0.1:7005@17005 master - 0 1586210953749 7 connected 0-5460
- 9d6d78888e579442b209fca95af13b6ece4810b6 127.0.0.1:7004@17004 slave 6494df31d4ed564d80947c9d39369cc7cfb6c0e6 0 1586210953547 4 connected
- 981ad9769245c140c0bd9ee239472dc6e2cb07eb 127.0.0.1:7006@17006 slave d7a0d77d2f0fa05ccf4a14e379b52044b212607e 0 1586210952000 6 connected
- d7a0d77d2f0fa05ccf4a14e379b52044b212607e 127.0.0.1:7002@17002 myself,master - 0 1586210952000 2 connected 5461-10922
- 6494df31d4ed564d80947c9d39369cc7cfb6c0e6 127.0.0.1:7003@17003 master - 0 1586210952538 3 connected 10923-16383
- 4c7fcd06c55ceec27b5bbc450b99159282e7783e 127.0.0.1:7001@17001 master,fail - 1586210920633 1586210919825 1 disconnected
可以看到原先7001节点断开连接,其slave节点7005顶替了7001节点,变成了master节点,并继承了原先7001节点的slot槽。
当我们重新启动7001节点后,7001节点便作为7005的slave节点重新上线:
- 127.0.0.1:7002> cluster nodes
- 8891bfe505da42298be048364ed003b83dc52139 127.0.0.1:7005@17005 master - 0 1586211138837 7 connected 0-5460
- 9d6d78888e579442b209fca95af13b6ece4810b6 127.0.0.1:7004@17004 slave 6494df31d4ed564d80947c9d39369cc7cfb6c0e6 0 1586211138331 4 connected
- 981ad9769245c140c0bd9ee239472dc6e2cb07eb 127.0.0.1:7006@17006 slave d7a0d77d2f0fa05ccf4a14e379b52044b212607e 0 1586211139548 6 connected
- d7a0d77d2f0fa05ccf4a14e379b52044b212607e 127.0.0.1:7002@17002 myself,master - 0 1586211138000 2 connected 5461-10922
- 6494df31d4ed564d80947c9d39369cc7cfb6c0e6 127.0.0.1:7003@17003 master - 0 1586211139000 3 connected 10923-16383
- 4c7fcd06c55ceec27b5bbc450b99159282e7783e 127.0.0.1:7001@17001 slave 8891bfe505da42298be048364ed003b83dc52139 0 1586211137522 7 connected
由于我们Redis集群是有能力限制的,当不能满足当下要求的时候,就需要进行扩容,这事就涉及到水平扩展,我们先增加两份配置文件redis7007.conf、redis7008.conf,并创建两个节点并启动:
- 192:conf houjing$ /Volumes/work/redis-5.0.8/src/redis-server /Volumes/work/redis-5.0.8/conf/7007/redis7007.conf
- 192:conf houjing$ /Volumes/work/redis-5.0.8/src/redis-server /Volumes/work/redis-5.0.8/conf/7008/redis7008.conf
- 192:conf houjing$ ps -ef |grep redis
- 501 43018 1 0 5:47上午 ?? 0:06.27 /Volumes/work/redis-5.0.8/src/redis-server *:7002 [cluster]
- 501 43020 1 0 5:47上午 ?? 0:06.29 /Volumes/work/redis-5.0.8/src/redis-server *:7003 [cluster]
- 501 43022 1 0 5:47上午 ?? 0:06.29 /Volumes/work/redis-5.0.8/src/redis-server *:7004 [cluster]
- 501 43024 1 0 5:47上午 ?? 0:06.25 /Volumes/work/redis-5.0.8/src/redis-server *:7005 [cluster]
- 501 43026 1 0 5:47上午 ?? 0:06.24 /Volumes/work/redis-5.0.8/src/redis-server *:7006 [cluster]
- 501 43109 1 0 6:12上午 ?? 0:01.31 /Volumes/work/redis-5.0.8/src/redis-server *:7001 [cluster]
- 501 43141 1 0 6:18上午 ?? 0:00.03 /Volumes/work/redis-5.0.8/src/redis-server *:7007 [cluster]
- 501 43143 1 0 6:18上午 ?? 0:00.03 /Volumes/work/redis-5.0.8/src/redis-server *:7008 [cluster]
但是我们可以看到虽然进程启动了,但是并未加到集群中去:
- 127.0.0.1:7002> cluster nodes
- 8891bfe505da42298be048364ed003b83dc52139 127.0.0.1:7005@17005 master - 0 1586211626238 7 connected 0-5460
- 9d6d78888e579442b209fca95af13b6ece4810b6 127.0.0.1:7004@17004 slave 6494df31d4ed564d80947c9d39369cc7cfb6c0e6 0 1586211626741 4 connected
- 981ad9769245c140c0bd9ee239472dc6e2cb07eb 127.0.0.1:7006@17006 slave d7a0d77d2f0fa05ccf4a14e379b52044b212607e 0 1586211626036 6 connected
- d7a0d77d2f0fa05ccf4a14e379b52044b212607e 127.0.0.1:7002@17002 myself,master - 0 1586211625000 2 connected 5461-10922
- 6494df31d4ed564d80947c9d39369cc7cfb6c0e6 127.0.0.1:7003@17003 master - 0 1586211626540 3 connected 10923-16383
- 4c7fcd06c55ceec27b5bbc450b99159282e7783e 127.0.0.1:7001@17001 slave 8891bfe505da42298be048364ed003b83dc52139 0 1586211627751 7 connected
执行集群节点并没有返现我们的节点数据,这个时候需要把启动的节点数据增加到集群中去,执行命令:./redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7005:
- 192:src houjing$ ./redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7001
- >>> Adding node 127.0.0.1:7007 to cluster 127.0.0.1:7001
- >>> Performing Cluster Check (using node 127.0.0.1:7001)
- M: e83dc175f217148444a07ed367fea54ed6b3e2aa 127.0.0.1:7001
- slots:[0-5460] (5461 slots) master
- 1 additional replica(s)
- S: 4686809f8673bc918f03fd8642c410c1ca647a39 127.0.0.1:7004
- slots: (0 slots) slave
- replicates a3b2d4619e3ad17ea86f69a05543b12aa722a864
- S: 10eed7c7bbbd7e9e427d0ccf7e2d557607d7467f 127.0.0.1:7005
- slots: (0 slots) slave
- replicates de6820c4780a070ac658ee4bdf98c44b46038d81
- M: de6820c4780a070ac658ee4bdf98c44b46038d81 127.0.0.1:7003
- slots:[10923-16383] (5461 slots) master
- 1 additional replica(s)
- S: 9624c69e40a36dd1d67fbd21cae75753735f3f02 127.0.0.1:7006
- slots: (0 slots) slave
- replicates e83dc175f217148444a07ed367fea54ed6b3e2aa
- M: a3b2d4619e3ad17ea86f69a05543b12aa722a864 127.0.0.1:7002
- slots:[5461-10922] (5462 slots) master
- 1 additional replica(s)
- [OK] All nodes agree about slots configuration.
- >>> Check for open slots...
- >>> Check slots coverage...
- [OK] All 16384 slots covered.
- >>> Send CLUSTER MEET to node 127.0.0.1:7007 to make it join the cluster.
- [OK] New node added correctly.
-
- 127.0.0.1:7005> cluster nodes
- de6820c4780a070ac658ee4bdf98c44b46038d81 127.0.0.1:7003@17003 master - 0 1586212133524 3 connected 10923-16383
- e83dc175f217148444a07ed367fea54ed6b3e2aa 127.0.0.1:7001@17001 master - 0 1586212134536 1 connected 0-5460
- a3b2d4619e3ad17ea86f69a05543b12aa722a864 127.0.0.1:7002@17002 master - 0 1586212133323 2 connected 5461-10922
- 4686809f8673bc918f03fd8642c410c1ca647a39 127.0.0.1:7004@17004 slave a3b2d4619e3ad17ea86f69a05543b12aa722a864 0 1586212133000 4 connected
- a8236394ddd7f210e4df2036bd73968503283cf8 127.0.0.1:7007@17007 master - 0 1586212134333 0 connected
- 10eed7c7bbbd7e9e427d0ccf7e2d557607d7467f 127.0.0.1:7005@17005 myself,slave de6820c4780a070ac658ee4bdf98c44b46038d81 0 1586212134000 5 connected
- 9624c69e40a36dd1d67fbd21cae75753735f3f02 127.0.0.1:7006@17006 slave e83dc175f217148444a07ed367fea54ed6b3e2aa 0 1586212134000 6 connected
可以看到7007成功加入到集群节点,但是并未分配slot槽,接下来使用redis-cli命令为7007分配hash槽,找到集群中的任意一个主节点(7001),对其进行重新分片工作。命令: ./redis-cli --cluster reshard 127.0.0.1:7001
- 192:src houjing$ ./redis-cli --cluster reshard 127.0.0.1:7001
- >>> Performing Cluster Check (using node 127.0.0.1:7001)
- M: e83dc175f217148444a07ed367fea54ed6b3e2aa 127.0.0.1:7001
- slots:[0-5460] (5461 slots) master
- 1 additional replica(s)
- S: 4686809f8673bc918f03fd8642c410c1ca647a39 127.0.0.1:7004
- slots: (0 slots) slave
- replicates a3b2d4619e3ad17ea86f69a05543b12aa722a864
- S: 10eed7c7bbbd7e9e427d0ccf7e2d557607d7467f 127.0.0.1:7005
- slots: (0 slots) slave
- replicates de6820c4780a070ac658ee4bdf98c44b46038d81
- M: de6820c4780a070ac658ee4bdf98c44b46038d81 127.0.0.1:7003
- slots:[10923-16383] (5461 slots) master
- 1 additional replica(s)
- S: 9624c69e40a36dd1d67fbd21cae75753735f3f02 127.0.0.1:7006
- slots: (0 slots) slave
- replicates e83dc175f217148444a07ed367fea54ed6b3e2aa
- M: a8236394ddd7f210e4df2036bd73968503283cf8 127.0.0.1:7007
- slots: (0 slots) master
- M: a3b2d4619e3ad17ea86f69a05543b12aa722a864 127.0.0.1:7002
- slots:[5461-10922] (5462 slots) master
- 1 additional replica(s)
- [OK] All nodes agree about slots configuration.
- >>> Check for open slots...
- >>> Check slots coverage...
- [OK] All 16384 slots covered.
- How many slots do you want to move (from 1 to 16384)? 1000
- What is the receiving node ID? a8236394ddd7f210e4df2036bd73968503283cf8
- Please enter all the source node IDs.
- Type 'all' to use all the nodes as source nodes for the hash slots.
- Type 'done' once you entered all the source nodes IDs.
- Source node #1: all
以上就是要从其余三个master上划分1000个slot到7007节点,7007节点的ID为a8236394ddd7f210e4df2036bd73968503283cf8。两种reshard方式如下:
备注:all是随机的,比如说我们要分出1000个,则3个主节点分别拿出333个,333个,334个节点分别给7007。
此时查看cluster nodes信息如下:
- 127.0.0.1:7005> cluster nodes
- de6820c4780a070ac658ee4bdf98c44b46038d81 127.0.0.1:7003@17003 master - 0 1586212646000 3 connected 11256-16383
- e83dc175f217148444a07ed367fea54ed6b3e2aa 127.0.0.1:7001@17001 master - 0 1586212645158 1 connected 333-5460
- a3b2d4619e3ad17ea86f69a05543b12aa722a864 127.0.0.1:7002@17002 master - 0 1586212646000 2 connected 5795-10922
- 4686809f8673bc918f03fd8642c410c1ca647a39 127.0.0.1:7004@17004 slave a3b2d4619e3ad17ea86f69a05543b12aa722a864 0 1586212646572 4 connected
- a8236394ddd7f210e4df2036bd73968503283cf8 127.0.0.1:7007@17007 master - 0 1586212646372 7 connected 0-332 5461-5794 10923-11255
- 10eed7c7bbbd7e9e427d0ccf7e2d557607d7467f 127.0.0.1:7005@17005 myself,slave de6820c4780a070ac658ee4bdf98c44b46038d81 0 1586212645000 5 connected
- 9624c69e40a36dd1d67fbd21cae75753735f3f02 127.0.0.1:7006@17006 slave e83dc175f217148444a07ed367fea54ed6b3e2aa 0 1586212645000 6 connected
可以看到7007节点拿到了3段合计1000个slot槽,接下来我们为7007增加从节点7008,依旧是先把7008添加到集群中去:./redis-cli --cluster add-node 127.0.0.1:7008 127.0.0.1:7001:
- 127.0.0.1:7005> cluster nodes
- d9daa198ebe389f7c707e6d41c8052e59f29ce0b 127.0.0.1:7008@17008 master - 0 1586212814000 0 connected
- de6820c4780a070ac658ee4bdf98c44b46038d81 127.0.0.1:7003@17003 master - 0 1586212814970 3 connected 11256-16383
- e83dc175f217148444a07ed367fea54ed6b3e2aa 127.0.0.1:7001@17001 master - 0 1586212815000 1 connected 333-5460
- a3b2d4619e3ad17ea86f69a05543b12aa722a864 127.0.0.1:7002@17002 master - 0 1586212815000 2 connected 5795-10922
- 4686809f8673bc918f03fd8642c410c1ca647a39 127.0.0.1:7004@17004 slave a3b2d4619e3ad17ea86f69a05543b12aa722a864 0 1586212814565 4 connected
- a8236394ddd7f210e4df2036bd73968503283cf8 127.0.0.1:7007@17007 master - 0 1586212815574 7 connected 0-332 5461-5794 10923-11255
- 10eed7c7bbbd7e9e427d0ccf7e2d557607d7467f 127.0.0.1:7005@17005 myself,slave de6820c4780a070ac658ee4bdf98c44b46038d81 0 1586212815000 5 connected
- 9624c69e40a36dd1d67fbd21cae75753735f3f02 127.0.0.1:7006@17006 slave e83dc175f217148444a07ed367fea54ed6b3e2aa 0 1586212814565 6 connected
可以看到7008添加到了集群,但是目前还是主节点,并且没有hash槽。接下来需要让其变成从节点。
命令:CLUSTER REPLICATE a8236394ddd7f210e4df2036bd73968503283cf8(这个节点给哪个主节点)
- 192:src houjing$ ./redis-cli -c -p 7008
- 127.0.0.1:7008> CLUSTER REPLICATE a8236394ddd7f210e4df2036bd73968503283cf8
- OK
- 127.0.0.1:7008> cluster nodes
- 4686809f8673bc918f03fd8642c410c1ca647a39 127.0.0.1:7004@17004 slave a3b2d4619e3ad17ea86f69a05543b12aa722a864 0 1586213074000 2 connected
- a8236394ddd7f210e4df2036bd73968503283cf8 127.0.0.1:7007@17007 master - 0 1586213073000 7 connected 0-332 5461-5794 10923-11255
- 9624c69e40a36dd1d67fbd21cae75753735f3f02 127.0.0.1:7006@17006 slave e83dc175f217148444a07ed367fea54ed6b3e2aa 0 1586213073000 1 connected
- de6820c4780a070ac658ee4bdf98c44b46038d81 127.0.0.1:7003@17003 master - 0 1586213074818 3 connected 11256-16383
- e83dc175f217148444a07ed367fea54ed6b3e2aa 127.0.0.1:7001@17001 master - 0 1586213074000 1 connected 333-5460
- d9daa198ebe389f7c707e6d41c8052e59f29ce0b 127.0.0.1:7008@17008 myself,slave a8236394ddd7f210e4df2036bd73968503283cf8 0 1586213073000 0 connected
- a3b2d4619e3ad17ea86f69a05543b12aa722a864 127.0.0.1:7002@17002 master - 0 1586213074513 2 connected 5795-10922
- 10eed7c7bbbd7e9e427d0ccf7e2d557607d7467f 127.0.0.1:7005@17005 slave a8236394ddd7f210e4df2036bd73968503283cf8 0 1586213074513 7 connected
如上所示,查看cluster nodes信息则可直到成功实现Redis集群的水平扩容。
我们现实中存在着水平扩展,那么当服务使用量下降时,也存在着节点下线。比如我们要让刚扩容的7007、7008下线,我们先来删除从节点7008:
命令:./redis-cli --cluster del-node 127.0.0.1:7008 d9daa198ebe389f7c707e6d41c8052e59f29ce0b
- 192:src houjing$ ./redis-cli --cluster del-node 127.0.0.1:7008 d9daa198ebe389f7c707e6d41c8052e59f29ce0b
- >>> Removing node d9daa198ebe389f7c707e6d41c8052e59f29ce0b from cluster 127.0.0.1:7008
- >>> Sending CLUSTER FORGET messages to the cluster...
- >>> SHUTDOWN the node.
-
- 127.0.0.1:7001> cluster nodes
- 4686809f8673bc918f03fd8642c410c1ca647a39 127.0.0.1:7004@17004 slave a3b2d4619e3ad17ea86f69a05543b12aa722a864 0 1586213383501 4 connected
- e83dc175f217148444a07ed367fea54ed6b3e2aa 127.0.0.1:7001@17001 myself,master - 0 1586213383000 1 connected 333-5460
- 10eed7c7bbbd7e9e427d0ccf7e2d557607d7467f 127.0.0.1:7005@17005 slave a8236394ddd7f210e4df2036bd73968503283cf8 0 1586213383000 7 connected
- de6820c4780a070ac658ee4bdf98c44b46038d81 127.0.0.1:7003@17003 master - 0 1586213383000 3 connected 11256-16383
- 9624c69e40a36dd1d67fbd21cae75753735f3f02 127.0.0.1:7006@17006 slave e83dc175f217148444a07ed367fea54ed6b3e2aa 0 1586213384308 6 connected
- a8236394ddd7f210e4df2036bd73968503283cf8 127.0.0.1:7007@17007 master - 0 1586213383300 7 connected 0-332 5461-5794 10923-11255
- a3b2d4619e3ad17ea86f69a05543b12aa722a864 127.0.0.1:7002@17002 master - 0 1586213383000 2 connected 5795-10922
接下来删除主节点7007,命令:./redis-cli --cluster reshard 127.0.0.1:7007
- 192:src houjing$ ./redis-cli --cluster reshard 127.0.0.1:7007
- >>> Performing Cluster Check (using node 127.0.0.1:7007)
- M: a8236394ddd7f210e4df2036bd73968503283cf8 127.0.0.1:7007
- slots:[172-665],[5461-6128],[10923-11588] (1828 slots) master
- 1 additional replica(s)
- M: a3b2d4619e3ad17ea86f69a05543b12aa722a864 127.0.0.1:7002
- slots:[6542-10922] (4381 slots) master
- 1 additional replica(s)
- S: 4686809f8673bc918f03fd8642c410c1ca647a39 127.0.0.1:7004
- slots: (0 slots) slave
- replicates a3b2d4619e3ad17ea86f69a05543b12aa722a864
- M: de6820c4780a070ac658ee4bdf98c44b46038d81 127.0.0.1:7003
- slots:[12003-16383] (4381 slots) master
- S: 9624c69e40a36dd1d67fbd21cae75753735f3f02 127.0.0.1:7006
- slots: (0 slots) slave
- replicates e83dc175f217148444a07ed367fea54ed6b3e2aa
- M: e83dc175f217148444a07ed367fea54ed6b3e2aa 127.0.0.1:7001
- slots:[0-171],[666-5460],[6129-6541],[11589-12002] (5794 slots) master
- 1 additional replica(s)
- S: 10eed7c7bbbd7e9e427d0ccf7e2d557607d7467f 127.0.0.1:7005
- slots: (0 slots) slave
- replicates a8236394ddd7f210e4df2036bd73968503283cf8
- [OK] All nodes agree about slots configuration.
- >>> Check for open slots...
- >>> Check slots coverage...
- [OK] All 16384 slots covered.
- How many slots do you want to move (from 1 to 16384)? 1828
- What is the receiving node ID? a3b2d4619e3ad17ea86f69a05543b12aa722a864
- Please enter all the source node IDs.
- Type 'all' to use all the nodes as source nodes for the hash slots.
- Type 'done' once you entered all the source nodes IDs.
- Source node #1: a8236394ddd7f210e4df2036bd73968503283cf8
- Source node #2: done
-
- Ready to move 1828 slots.
可以看到我们把7007节点的1828个slot全部移到了7002上,再次查看cluster nodes信息如下:
- 127.0.0.1:7001> cluster nodes
- 4686809f8673bc918f03fd8642c410c1ca647a39 127.0.0.1:7004@17004 slave a3b2d4619e3ad17ea86f69a05543b12aa722a864 0 1586214201506 9 connected
- e83dc175f217148444a07ed367fea54ed6b3e2aa 127.0.0.1:7001@17001 myself,master - 0 1586214200000 8 connected 0-171 666-5460 6129-6541 11589-12002
- 10eed7c7bbbd7e9e427d0ccf7e2d557607d7467f 127.0.0.1:7005@17005 slave a3b2d4619e3ad17ea86f69a05543b12aa722a864 0 1586214201000 9 connected
- de6820c4780a070ac658ee4bdf98c44b46038d81 127.0.0.1:7003@17003 master - 0 1586214200000 3 connected 12003-16383
- 9624c69e40a36dd1d67fbd21cae75753735f3f02 127.0.0.1:7006@17006 slave e83dc175f217148444a07ed367fea54ed6b3e2aa 0 1586214200000 8 connected
- a8236394ddd7f210e4df2036bd73968503283cf8 127.0.0.1:7007@17007 master - 0 1586214201707 7 connected
- a3b2d4619e3ad17ea86f69a05543b12aa722a864 127.0.0.1:7002@17002 master - 0 1586214201000 9 connected 172-665 5461-6128 6542-11588
7007节点还在,但是分配的slot没有了,接下来关闭7007节点,命令:./redis-cli -p 7001 shutdown
- 127.0.0.1:7001> cluster nodes
- a8236394ddd7f210e4df2036bd73968503283cf8 127.0.0.1:7007@17007 master - 1586214471239 1586214469000 7 disconnected
- 4686809f8673bc918f03fd8642c410c1ca647a39 127.0.0.1:7004@17004 slave a3b2d4619e3ad17ea86f69a05543b12aa722a864 0 1586214473159 9 connected
- e83dc175f217148444a07ed367fea54ed6b3e2aa 127.0.0.1:7001@17001 myself,slave 9624c69e40a36dd1d67fbd21cae75753735f3f02 0 1586214473000 8 connected
- de6820c4780a070ac658ee4bdf98c44b46038d81 127.0.0.1:7003@17003 master - 0 1586214473000 3 connected 12003-16383
- 9624c69e40a36dd1d67fbd21cae75753735f3f02 127.0.0.1:7006@17006 master - 0 1586214472653 10 connected 0-171 666-5460 6129-6541 11589-12002
- a3b2d4619e3ad17ea86f69a05543b12aa722a864 127.0.0.1:7002@17002 master - 0 1586214474073 9 connected 172-665 5461-6128 6542-11588
- 10eed7c7bbbd7e9e427d0ccf7e2d557607d7467f 127.0.0.1:7005@17005 slave 9624c69e40a36dd1d67fbd21cae75753735f3f02 0 1586214474175 10 connected
于是实现了7007、7008节点的下线。
需要修改redis.conf 配置文件
cluster-enable yes # 表示这个Redis 是一个cluster节点
cluster-config-file [filename.conf] # cluster的配置文件
cluster-node-timeout 10000 # 节点服务超时时间,用于判定该节点是否下线或切换为从节点
cluster集群中各个redis依次启动完成后,需要使用
./redis-trib.rb create --replicas 1 ip1:port1 ip2:port2 ip3:port3 ip4:port4 ip5:port5 ip6:port6
create 代表创建集群
--replicas: 指定内部结构 1:代表一个master连接一个slave节点 ip1:port1->ip4:port4 ip2:port2->ip5:port5 ip3:port3->ip6:port6
2: 代表一个master连接两个slave节点 ip1:port1->ip3:port3,ip4:port4 ip2:port2->ip5:port5,ip6:port6
cluster集群搭建好之后,需要注意的是要使用 redis-cli -c 来连接 cluster集群。
Redis-Cluster 支持动态的新增和删除节点
新增
./redis-trib.rb add-node [ip1:port1] [ip2:port],新增成功后我们可以通过 cluster nodes 命令查看集群节点信息,我们可以看到 新增的节点是没有被分配 slot槽的。
手动分配槽节点
cluster setslot 5462 node e4fee6a90d5b071ad514cd30f8d5d9a1c13947b3
cluster setslot [槽] node [目标id]
自动分配槽节点
./redis-trib.rb reshard ip:port
删除
对于已经分配了槽区间的节点,我们是无法直接删除的,需要先将槽区间分配出去,然后再进行删除
将槽区间分配到其他节点
./redis-trib.rb reshard ip:port
删除命令
./redis-trib.rb del-node ip:port 目标id
运维:终于不用再背着数万实例的Redis集群了!_Cluster
Redis学习之4种模式实践及机制解析(单机、主从、哨兵、集群)