一、Redis Cluster 分布式分片集群 Redis Cluster简介
Redis集群是一个可以在多个Redis节点之间进行数据共享的设施(installation)。
Redis集群不支持那些需要同时处理多个键的Redis命令,因为执行这些命令需要在多个Redis节点之间移动数据,并且在高负载的情况下,这些命令将降低Redis集群的性能,并导致不可预测的行为。
Redis集群通过分区(partition)来提供一定程度的可用性(availability):即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求。
Redis集群有将数据自动切分(split)到多个节点的能力。
Redis Cluster中槽(slot)的概念
Redis Cluster中一共有16384个槽位,他们的编号为0、1、2、3……16382、16383,这些槽是虚拟的。
这些槽位会平均分配给Redis Cluster中的每个master节点,当有某个key被映射到某个master负责的槽,那么这个master负责为这个key提供服务。
当需要在redis集群中写入一个key -value的时候,会使用HASH_SLOT=CRC16(key) mod 16384之后的值,决定将key写入值哪一个槽位从而决定写入哪一个Redis节点上,从而有效解决单机瓶颈。
在Redis Cluster中,只有master才拥有槽的所有权,如果是某个master的slave,这个slave只负责槽的使用,但是没有所有权。
Redis Cluster的特点
解决了redis资源利用率的问题
所有Redis节点使用(PING机制)互联
在多分片节点中,将16384个槽位,均匀分布到多个分片节点中
存数据时,将key做crc16(key),然后和16384进行取模,得出槽位值(0-16383之间)
根据计算得出的槽位值,找到相对应的分片节点的主节点,存储到相应槽位上
如果客户端当时连接的节点不是将来要存储的分片节点,分片集群会将客户端连接切换至真正存储节点进行数据存储
在搭建集群时,会为每一个分片的主节点,对应一个从节点,实现slaveof功能,同时当主节点down,实现类似于sentinel的自动failover的功能。
Redis Cluster运行机制
所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
节点的fail是通过集群中超过半数的master节点检测失效时才生效。
客户端与redis节点直连,不需要中间proxy层。客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->key
Redis Cluster故障转移
在集群里面,节点会对其他节点进行下线检测。
当一个主节点下线时,集群里面的其他主节点负责对下线主节点进行故障移。
换句话说,集群的节点集成了下线检测和故障转移等类似 Sentinel 的功能。
因为 Sentinel 是一个独立运行的监控程序,而集群的下线检测和故障转移等功能是集成在节点里面的,它们的运行模式非常地不同,所以尽管这两者的功能很相似,但集群的实现没有重用 Sentinel 的代码。
二、Redis Cluster 分布式集群搭建 Redis Cluster 架构图:
1.部署Redis Cluster 环境规划
节点
主机名
IP
端口
node1
redis-01
172.16.1.56
6379, 6380
node2
redis-02
172.16.1.57
6379, 6380
node3
redis-03
172.16.1.58
6379, 6380
创建Redis工作目录 [root@redis-01 ~] [root@redis-02 ~] [root@redis-03 ~]
配置每个Redis节点
[root@redis-01 ~] bind 172.16.1.56 127.0.0.1port 6379 daemonize yes pidfile "/service/redis/6379/redis.pid" loglevel notice logfile "/service/redis/6379/redis.log" protected-mode no dir "/service/redis/6379" dbfilename dump.rdb save 900 1 save 300 10 save 60 10000 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 [root@redis-01 ~] bind 172.16.1.56 127.0.0.1port 6380 daemonize yes pidfile "/service/redis/6380/redis.pid" loglevel notice logfile "/service/redis/6380/redis.log" protected-mode no dir "/service/redis/6380" dbfilename dump.rdb save 900 1 save 300 10 save 60 10000 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000
[root@redis-02 ~] bind 172.16.1.57 127.0.0.1port 6379 daemonize yes pidfile "/service/redis/6379/redis.pid" loglevel notice logfile "/service/redis/6379/redis.log" protected-mode no dir "/service/redis/6379" dbfilename dump.rdb save 900 1 save 300 10 save 60 10000 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 [root@redis-02 ~] bind 172.16.1.57 127.0.0.1port 6380 daemonize yes pidfile "/service/redis/6380/redis.pid" loglevel notice logfile "/service/redis/6380/redis.log" protected-mode no dir "/service/redis/6380" dbfilename dump.rdb save 900 1 save 300 10 save 60 10000 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000
[root@redis-03 ~] bind 172.16.1.58 127.0.0.1port 6379 daemonize yes pidfile "/service/redis/6379/redis.pid" loglevel notice logfile "/service/redis/6379/redis.log" protected-mode no dir "/service/redis/6379" dbfilename dump.rdb save 900 1 save 300 10 save 60 10000 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 [root@redis-03 ~] bind 172.16.1.58 127.0.0.1port 6380 daemonize yes pidfile "/service/redis/6380/redis.pid" loglevel notice logfile "/service/redis/6380/redis.log" protected-mode no dir "/service/redis/6380" dbfilename dump.rdb save 900 1 save 300 10 save 60 10000 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000
启动每个节点的所有Redis实例
[root@redis-01 ~] [root@redis-02 ~] [root@redis-03 ~] [root@redis-01 ~] [root@redis-02 ~] [root@redis-03 ~]
[root@redis-01 6379] tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN tcp 0 0 172.16.1.56:6379 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:6380 0.0.0.0:* LISTEN tcp 0 0 172.16.1.56:6380 0.0.0.0:* LISTEN
将所有节点加入集群 一共有node1、node2、node3这三个节点,其中每个节点有2个实例(6379、6380)。
此时所有机器集群中都只有自己一个节点
172.16.1.56:6379> cluster nodes 98d2d1e2f97607d52585ea041db4b0e90ce06769 :6379 myself,master - 0 0 0 connected
把所有节点加入集群(可以在任何一个redis实例中操作)
172.16.1.56:6379> cluster meet 172.16.1.56 6380 OK 172.16.1.56:6379> cluster meet 172.16.1.57 6379 OK 172.16.1.56:6379> cluster meet 172.16.1.57 6380 OK 172.16.1.56:6379> cluster meet 172.16.1.58 6379 OK 172.16.1.56:6379> cluster meet 172.16.1.58 6380 OK
所有节点都成功加入了集群中,且每个节点都是master
给集群中的节点做主从 主从规划:
node1节点的6380实例作为node2节点的6379实例的从库。
node2节点的6380实例作为node3节点的6379实例的从库。
node3节点的6380实例作为node1节点的6379实例的从库。
这样任何一个节点宕机了,也能保证整个Redis Cluster 处于正常状态。
主节点:172.16.1.56:6379、172.16.1.57:6379、172.16.1.58:6379 从节点:172.16.1.56:6380、172.16.1.57:6380、172.16.1.58:6380
[root@redis-01 ~] 172.16.1.56:6380> cluster replicate 6af845e7ff405845605a418f976184f343764d17 OK [root@redis-02 ~] 172.16.1.57:6380> cluster replicate ae875d8a949e7ad62a3f5374db9de546afb6520d OK [root@redis-03 ~] 172.16.1.58:6380> cluster replicate 98d2d1e2f97607d52585ea041db4b0e90ce06769 OK
注意:* cluster replicate
命令后的ID是器主库的ID号*。
集群中存在master和slave,说明主从分配完成。
给集群分配槽位 槽位规划:
主机名
实例
槽位
redis-01
172.16.1.56:6379
0 ~ 5460
redis-02
172.16.1.57:6379
5461 ~ 10921
redis-03
172.16.1.58:6379
10922 ~ 16383
[root@redis-01 ~] OK [root@redis-01 ~] OK [root@redis-01 ~] OK
注意:槽位只分配给集群中的主节点
172.16.1.56:6379> cluster info cluster_state:ok cluster_slots_assigned:16384 cluster_slots_ok:16384 cluster_slots_pfail:0 cluster_slots_fail:0 cluster_known_nodes:6 cluster_size:3 cluster_current_epoch:5 cluster_my_epoch:3 cluster_stats_messages_sent:22785 cluster_stats_messages_received:22785
到这里,Redis Cluster 分布式集群搭建完成。
2.插入数据测试 172.16.1.56:6379> set k1 v1 (error) MOVED 12706 172.16.1.58:6379 172.16.1.56:6379> set k2 v2 OK [root@redis-01 ~] 172.16.1.58:6379> set k1 v1 OK -c 启用群集模式(遵循-ASK和-MOVED重定向) [root@redis-01 ~] 172.16.1.56:6379> set k1 v1 -> Redirected to slot [12706] located at 172.16.1.58:6379 OK [root@redis-01 ~] [root@redis-01 ~] 172.16.1.56:6379> dbsize (integer ) 3344 [root@redis-01 ~] 172.16.1.57:6379> dbsize (integer ) 3314 [root@redis-01 ~] 172.16.1.58:6379> dbsize (integer ) 3344
三、Redis Cluster 集群管理操作(核心) 1.安装集群管理插件 安装ruby插件
查看当前的gem源
[root@redis-01 ~] *** CURRENT SOURCES *** http://rubygems.org/
添加阿里云的gem源
[root@redis-01 ~] http://mirrors.aliyun.com/rubygems/ added to source
删除国外gem源
[root@redis-01 ~] https://rubygems.org/ removed from sources
再次查看gem源,已经替换成阿里的了
[root@redis-01 ~] *** CURRENT SOURCES *** http://mirrors.aliyun.com/rubygems/
[root@redis-01 ~] Fetching: redis-3.3.3.gem (100%) Successfully installed redis-3.3.3 Parsing documentation for redis-3.3.3 Installing ri documentation for redis-3.3.3 1 gem installed
ruby插件使用说明 redis的ruby插件安装好后,redis就可以使用redis-trib.rb
命令了。
命令参数说明:
[root@redis-01 ~] create check info fix reshard rebalance add-node del-node set-timeout 1call 1import
2.添加新节点到Redis Cluster 在另外一台机新机器上,准备两个实例。(生产环境)
这里我就不新加服务器了,直接在redis-03上再添加2个实例( 172.16.1.58:6381
、172.16.1.58:6382
)。
创建实例工作目录
配置两个实例
[root@redis-03 ~] bind 172.16.1.58 127.0.0.1port 6381 daemonize yes pidfile "/service/redis/6381/redis.pid" loglevel notice logfile "/service/redis/6381/redis.log" protected-mode no dir "/service/redis/6381" dbfilename dump.rdb save 900 1 save 300 10 save 60 10000 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000
[root@redis-03 ~] bind 172.16.1.58 127.0.0.1port 6382 daemonize yes pidfile "/service/redis/6382/redis.pid" loglevel notice logfile "/service/redis/6382/redis.log" protected-mode no dir "/service/redis/6382" dbfilename dump.rdb save 900 1 save 300 10 save 60 10000 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000
启动实例
[root@redis-03 ~] [root@redis-03 ~]
[root@redis-03 ~] tcp 0 0 127.0.0.1:6381 0.0.0.0:* LISTEN tcp 0 0 172.16.1.58:6381 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:6382 0.0.0.0:* LISTEN tcp 0 0 172.16.1.58:6382 0.0.0.0:* LISTEN
将新节点加入到集群中
172.16.1.56:6379> cluster meet 172.16.1.58 6381 OK 172.16.1.56:6379> cluster meet 172.16.1.58 6382 OK
6381和6382这两个实例已经加入到集群中。
给新添加的节点分配主从 由于原来的集群主从节点已经分配好了,现在新加入2个实例,所以这里需要稍微改动下集群中的主从规划
改动信息为:172.16.1.58:6380
为 172.16.1.58:6381
的从库,172.16.1.58:6382
为 172.16.1.56:6379
的从库。
给172.16.1.58:6380指定新的主节点为172.16.1.58:6381
[root@redis-01 ~] 172.16.1.58:6380> cluster replicate fe38fef7425262fd0a98ab494d31312f4d755fc5 OK
给172.16.1.58:6382指定主节点为172.16.1.56:6379
[root@redis-01 ~] 172.16.1.58:6382> cluster replicate 98d2d1e2f97607d52585ea041db4b0e90ce06769 OK
6381和6382已经处于主从状态了
重新给集群分配槽位 新节点加入集群后,发现 172.16.1.58:6381
节点并没有槽位,所以这里需要给它分配槽位。
[root@redis-01 ~] >>> Performing Cluster Check (using node 172.16.1.58:6381) M: fe38fef7425262fd0a98ab494d31312f4d755fc5 172.16.1.58:6381 slots: (0 slots) master 1 additional replica(s) M: 98d2d1e2f97607d52585ea041db4b0e90ce06769 172.16.1.56:6379 slots:0-5460 (5461 slots) master 1 additional replica(s) M: ae875d8a949e7ad62a3f5374db9de546afb6520d 172.16.1.58:6379 slots:10922-16383 (5462 slots) master 1 additional replica(s) S: b77db6765e079f5b50cbd0c168cc4d3062208b15 172.16.1.57:6380 slots: (0 slots) slave replicates ae875d8a949e7ad62a3f5374db9de546afb6520d S: a0e86878dc86ce6ff49aa27fa82b246adf938fd5 172.16.1.58:6382 slots: (0 slots) slave replicates 98d2d1e2f97607d52585ea041db4b0e90ce06769 S: b91bd15633fc2b1d6d00c4d4ec405c3a9c6b5863 172.16.1.58:6380 slots: (0 slots) slave replicates fe38fef7425262fd0a98ab494d31312f4d755fc5 S: 208c6db915517ea7424acfca94f382eb7cf254d8 172.16.1.56:6380 slots: (0 slots) slave replicates 6af845e7ff405845605a418f976184f343764d17 M: 6af845e7ff405845605a418f976184f343764d17 172.16.1.57:6379 slots:5461-10921 (5461 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)? 4096 What is the receiving node ID? fe38fef7425262fd0a98ab494d31312f4d755fc5 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 Do you want to proceed with the proposed reshard plan (yes/no)?yes
使用redis-trib.rb
命令查看槽位
[root@redis-01 ~] 172.16.1.58:6381 (fe38fef7...) -> 2517 keys | 4096 slots | 1 slaves. 172.16.1.56:6379 (98d2d1e2...) -> 2498 keys | 4096 slots | 1 slaves. 172.16.1.58:6379 (ae875d8a...) -> 2502 keys | 4096 slots | 1 slaves. 172.16.1.57:6379 (6af845e7...) -> 2485 keys | 4096 slots | 1 slaves. [OK] 10002 keys in 4 masters. 0.61 keys per slot on average.
也可以通过查看集群方式查看槽位
3.删除Redis Cluster中的节点 删除集群中的节点,需要移除它的槽位(如果是主节)。并重新给集群分配槽位
重新分片 [root@redis-01 ~] >>> Performing Cluster Check (using node 172.16.1.58:6381) M: fe38fef7425262fd0a98ab494d31312f4d755fc5 172.16.1.58:6381 slots:0-1364,5461-6825,10922-12287 (4096 slots) master 1 additional replica(s) M: 98d2d1e2f97607d52585ea041db4b0e90ce06769 172.16.1.56:6379 slots:1365-5460 (4096 slots) master 1 additional replica(s) M: ae875d8a949e7ad62a3f5374db9de546afb6520d 172.16.1.58:6379 slots:12288-16383 (4096 slots) master 1 additional replica(s) S: b77db6765e079f5b50cbd0c168cc4d3062208b15 172.16.1.57:6380 slots: (0 slots) slave replicates ae875d8a949e7ad62a3f5374db9de546afb6520d S: a0e86878dc86ce6ff49aa27fa82b246adf938fd5 172.16.1.58:6382 slots: (0 slots) slave replicates 98d2d1e2f97607d52585ea041db4b0e90ce06769 S: b91bd15633fc2b1d6d00c4d4ec405c3a9c6b5863 172.16.1.58:6380 slots: (0 slots) slave replicates fe38fef7425262fd0a98ab494d31312f4d755fc5 S: 208c6db915517ea7424acfca94f382eb7cf254d8 172.16.1.56:6380 slots: (0 slots) slave replicates 6af845e7ff405845605a418f976184f343764d17 M: 6af845e7ff405845605a418f976184f343764d17 172.16.1.57:6379 slots:6826-10921 (4096 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)? 4096 What is the receiving node ID? 98d2d1e2f97607d52585ea041db4b0e90ce06769 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 Source node Do you want to proceed with the proposed reshard plan (yes/no)? yes
平衡槽位
发现 172.16.1.58:6381
节点没有槽位
查看其他节点的槽位大小,172.16.1.56:6379
最大有8192个槽位,其他两个节点都是4096个槽位。
使用redis-trib.rb rebalance
命令给这3个节点平均分配槽位
[root@redis-01 ~] >>> Performing Cluster Check (using node 172.16.1.56:6379) [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. >>> Rebalancing across 3 nodes. Total weight = 3 Moving 1366 slots from 172.16.1.56:6379 to 172.16.1.58:6379 Moving 1365 slots from 172.16.1.56:6379 to 172.16.1.57:6379
发现这3个主节点的槽位大小基本相等了。
删除节点 先查看6381(主节点)和6382(从节点)节点的ID信息,在进行删除。
主节点:
[root@redis-01 ~] fe38fef7425262fd0a98ab494d31312f4d755fc5 172.16.1.58:6381 master - 0 1594383787509 11 connected ae875d8a949e7ad62a3f5374db9de546afb6520d 172.16.1.58:6379 master - 0 1594383788516 13 connected 0-1365 12288-16383 6af845e7ff405845605a418f976184f343764d17 172.16.1.57:6379 master - 0 1594383788516 14 connected 1366-2730 6826-10921 98d2d1e2f97607d52585ea041db4b0e90ce06769 172.16.1.56:6379 myself,master - 0 0 12 connected 2731-6825 10922-12287
从节点:
[root@redis-01 ~] a0e86878dc86ce6ff49aa27fa82b246adf938fd5 172.16.1.58:6382 slave 98d2d1e2f97607d52585ea041db4b0e90ce06769 0 1594383794053 12 connected b91bd15633fc2b1d6d00c4d4ec405c3a9c6b5863 172.16.1.58:6380 slave 98d2d1e2f97607d52585ea041db4b0e90ce06769 0 1594383792036 12 connected 208c6db915517ea7424acfca94f382eb7cf254d8 172.16.1.56:6380 slave 6af845e7ff405845605a418f976184f343764d17 0 1594383792539 14 connected b77db6765e079f5b50cbd0c168cc4d3062208b15 172.16.1.57:6380 slave ae875d8a949e7ad62a3f5374db9de546afb6520d 0 1594383794053 13 connected
删除172.16.1.58:6381和172.16.1.58:6382两个节点
[root@redis-01 ~] >>> Removing node fe38fef7425262fd0a98ab494d31312f4d755fc5 from cluster 172.16.1.58:6381 >>> Sending CLUSTER FORGET messages to the cluster... >>> SHUTDOWN the node. [root@redis-01 ~] >>> Removing node a0e86878dc86ce6ff49aa27fa82b246adf938fd5 from cluster 172.16.1.58:6382 >>> Sending CLUSTER FORGET messages to the cluster... >>> SHUTDOWN the node.
发现172.16.1.58:6381和172.16.1.58:6382两个节点已经不存在于集群中了
[root@redis-01 ~] ae875d8a949e7ad62a3f5374db9de546afb6520d 172.16.1.58:6379 master - 0 1594384104291 13 connected 0-1365 12288-16383 6af845e7ff405845605a418f976184f343764d17 172.16.1.57:6379 master - 0 1594384103285 14 connected 1366-2730 6826-10921 b91bd15633fc2b1d6d00c4d4ec405c3a9c6b5863 172.16.1.58:6380 slave 98d2d1e2f97607d52585ea041db4b0e90ce06769 0 1594384103788 12 connected 208c6db915517ea7424acfca94f382eb7cf254d8 172.16.1.56:6380 slave 6af845e7ff405845605a418f976184f343764d17 0 1594384102780 14 connected b77db6765e079f5b50cbd0c168cc4d3062208b15 172.16.1.57:6380 slave ae875d8a949e7ad62a3f5374db9de546afb6520d 0 1594384102277 13 connected 98d2d1e2f97607d52585ea041db4b0e90ce06769 172.16.1.56:6379 myself,master - 0 0 12 connected 2731-6825 10922-12287
4.修复槽位分配故障 再给槽位进行重新分片时,由于意外导致分片中断,这样很可能造成槽位分配失败,集群出现故障。
模拟故障
执行从新分片操作时,在输入yes后,Ctrl + c 强制终止
然后使用redis-trib-rb check
检查集群
[root@redis-01 ~] >>> Check for open slots... [WARNING] Node 172.16.1.56:6379 has slots in importing state (52). [WARNING] Node 172.16.1.58:6379 has slots in migrating state (52). [WARNING] The following slots are open: 52 >>> Check slots coverage...
检查后,发现52槽位出现问题。
修复故障
使用redis-trib.rb fix
命令修复槽位