版权声明:本文为博主原创文章,未经博主容许不得转载。node
Redis
提供了灵活的节点扩容和收缩方案。在不影响集群对外服务的状况下,能够为集群添加节点进行扩容也能够对下线节点进行缩容。算法
咱们在Redis Cluster 介绍与搭建这篇文章中搭建了一个三主三从的Redis
集群(以下图所示)。在搭建 Redis Cluster 通讯流程剖析这篇博客中根据源码详细剖析了搭建集群的流程。数据库
本篇博客要讲的是,Redis
集群的扩容和缩容过程。安全
咱们先根据Redis Cluster 介绍与搭建将如图的集群搭建起来,查看搭建的效果。markdown
127.0.0.1:6379> cluster nodes 29978c0169ecc0a9054de7f4142155c1ab70258b 127.0.0.1:6379 myself,master - 0 0 7 connected 0-5461 8f285670923d4f1c599ecc93367c95a30fb8bf34 127.0.0.1:6380 master - 0 1496717082785 3 connected 5462-10922 66478bda726ae6ba4e8fb55034d8e5e5804223ff 127.0.0.1:6381 master - 0 1496717085793 2 connected 10923-16383 961097d6be64ebd2fd739ff719e97565a8cee7b5 127.0.0.1:6382 slave 29978c0169ecc0a9054de7f4142155c1ab70258b 0 1496717084791 7 connected 6fb7dfdb6188a9fe53c48ea32d541724f36434e9 127.0.0.1:6383 slave 8f285670923d4f1c599ecc93367c95a30fb8bf34 0 1496717087797 4 connected e0c7961a1b07ab655bc31d8dfd583da565ec167d 127.0.0.1:6384 slave 66478bda726ae6ba4e8fb55034d8e5e5804223ff 0 1496717086795 2 connected
对应的主节点负责的槽位信息,以下图所示:分布式
扩容集群是分布式存储最多见的需求,Redis
集群扩容能够分为以下步骤:工具
咱们须要两个节点,端口分别为6385
和6386
,配置和以前集群节点配置基本相同,除了端口不一样,以便于管理。6385
节点配置以下:post
port 6385 //端口 cluster-enabled yes //开启集群模式 cluster-config-file nodes-6385.conf //集群内部的配置文件 cluster-node-timeout 15000 //节点超时时间,单位毫秒 // 其余配置和单机模式相同
启动两个节点学习
sudo redis-server conf/redis-6385.conf sudo redis-server conf/redis-6386.conf
启动后的新节点会做为孤儿节点运行,没有和其余节点与之通讯。
咱们能够经过CLUSTER MEET
命令将6385
节点加入到集群中。
127.0.0.1:6379> CLUSTER MEET 127.0.0.1 6385 OK 127.0.0.1:6379> CLUSTER NODES cb987394a3acc7a5e606c72e61174b48e437cedb 127.0.0.1:6385 master - 0 1496731333689 8 connected ......
也可使用redis
专门进行集群管理的工具redis-trib.rb
,位于Redis
的源码目录中,把6386
节点加入到集群中
sudo src/redis-trib.rb add-node 127.0.0.1:6386 127.0.0.1:6379 127.0.0.1:6379> CLUSTER NODES cdfb1656353c5c7f29d0330a754c71d53cec464c 127.0.0.1:6386 master - 0 1496731447703 0 connected ......
这两种方法能够,新加入的节点都是主节点,由于没有负责槽位,因此不能接受任何读写操做,对于新加入的节点,咱们能够有两个操做:
当咱们将新节点加入集群后,咱们就能够将槽和数据迁移到新的节点,迁移的方法也有两种,可使用redis-trib.rb
工具,也能够经过手动命令的方式,可是通常要确保每一个主节点负责的槽数是均匀的,所以要使用redis-trib.rb
工具来批量完成,可是咱们只是为了演示迁移的过程,因此接下来手动使用命令进行迁移。
咱们先建立几个属于一个槽的键,将这些键迁移到新的节点中。
127.0.0.1:6379> SET key:{test}:555 value:test:555 -> Redirected to slot [6918] located at 127.0.0.1:6380 OK 127.0.0.1:6380> SET key:{test}:666 value:test:666 OK 127.0.0.1:6380> SET key:{test}:777 value:test:777 OK 127.0.0.1:6380> CLUSTER KEYSLOT key:{test}:555 (integer) 6918 127.0.0.1:6380> CLUSTER KEYSLOT key:{test}:666 (integer) 6918 127.0.0.1:6380> CLUSTER KEYSLOT key:{test}:777 (integer) 6918
原本在6379
节点中建立,可是重定向到了6380
节点中,由于咱们常见的键根据CRC16
算法计算分配到了6918
槽中,而这个槽由6380
节点负责。
若是键的名字中带有{}
,那么计算哈希值时就只计算{}
包含的字符串,因此建立的三个键属于一个槽。
计算哈希值的源码以下:
unsigned int keyHashSlot(char *key, int keylen) { int s, e; /* start-end indexes of { and } */ // 找'{'字符 for (s = 0; s < keylen; s++) if (key[s] == '{') break; // 没有找到"{}",直接计算整个key的哈希值 if (s == keylen) return crc16(key,keylen) & 0x3FFF; // 找到'{',检查是否有'}' for (e = s+1; e < keylen; e++) if (key[e] == '}') break; // 没有找到配对的'}',直接计算整个key的哈希值 if (e == keylen || e == s+1) return crc16(key,keylen) & 0x3FFF; // 若是找到了"{}",计算{}中间的哈希值 return crc16(key+s+1,e-s-1) & 0x3FFF; }
咱们已经获取了要迁移的槽,是6918
。所以,流程以下:
6385
节点中,将槽6918
设置为导入状态127.0.0.1:6385> CLUSTER SETSLOT 6918 importing 8f285670923d4f1c599ecc93367c95a30fb8bf34 OK // 8f285670923d4f1c599ecc93367c95a30fb8bf34 是 6380 节点的名字
目标6385
节点中,查看槽6918
导入状态
127.0.0.1:6385> CLUSTER NODES cb987394a3acc7a5e606c72e61174b48e437cedb 127.0.0.1:6385 myself,master - 0 0 8 connected [6918-<-8f285670923d4f1c599ecc93367c95a30fb8bf34]
6380
节点中,将槽6918
设置为导出状态127.0.0.1:6380> CLUSTER SETSLOT 6918 migrating cb987394a3acc7a5e606c72e61174b48e437cedb OK // cb987394a3acc7a5e606c72e61174b48e437cedb 是 6385 节点的名字
源6380
节点中,查看槽6918
导出状态
127.0.0.1:6380> CLUSTER NODES 8f285670923d4f1c599ecc93367c95a30fb8bf34 127.0.0.1:6380 myself,master - 0 0 3 connected 5462-10922 [6918->-cb987394a3acc7a5e606c72e61174b48e437cedb]
6918
中的键127.0.0.1:6380> CLUSTER GETKEYSINSLOT 6918 5 1) "key:{test}:555" 2) "key:{test}:666" 3) "key:{test}:777"
确认一下这三个键是否存在于源6380
节点。
127.0.0.1:6380> MGET key:{test}:777 key:{test}:666 key:{test}:555 1) "value:test:777" 2) "value:test:666" 3) "value:test:555"
migrate
命令进行迁移127.0.0.1:6380> MIGRATE 127.0.0.1 6385 "" 0 1000 keys key:{test}:777 key:{test}:666 key:{test}:555 OK
批量迁移版本的MIGRATE
命令是在redis 3.0.6
以后加入的,命令参数以下:
MIGRATE host port key dbid timeout [COPY | REPLACE]
MIGRATE host port "" dbid timeout [COPY | REPLACE] KEYS key1 key2 ... keyN // host port 指定迁移的目的节点地址 // dbid 指定迁移的数据库id // timeout 迁移的超时时间 // 若是指定了 COPY 选项,表示不删除源节点上的key // 若是指定了 REPLACE 选项,替换目标节点上已存在的key(若是存在)
当迁移完成后,咱们在源6380
节点查询这三个键,发送回复了一个ASK
错误
127.0.0.1:6380> MGET key:{test}:777 key:{test}:666 key:{test}:555 (error) ASK 6918 127.0.0.1:6385
最后,咱们只需向任意节点发送CLUSTER SETSLOT <slot> NODE <target_name>
命令,将槽指派的信息发送给节点,而后这个节点会将这个指派信息发送至整个集群。
CLUSTER SETSLOT 6918 node cb987394a3acc7a5e606c72e61174b48e437cedb // cb987394a3acc7a5e606c72e61174b48e437cedb 是 6385 节点的名字
在6381
节点执行命令
127.0.0.1:6381> CLUSTER SETSLOT 6918 node cb987394a3acc7a5e606c72e61174b48e437cedb OK
在6379
节点查看当前集群槽指派信息
127.0.0.1:6379> CLUSTER NODES 29978c0169ecc0a9054de7f4142155c1ab70258b 127.0.0.1:6379 myself,master - 0 0 7 connected 0-5461 66478bda726ae6ba4e8fb55034d8e5e5804223ff 127.0.0.1:6381 master - 0 1496736248776 2 connected 10923-16383 cb987394a3acc7a5e606c72e61174b48e437cedb 127.0.0.1:6385 master - 0 1496736244766 10 connected 6918 8f285670923d4f1c599ecc93367c95a30fb8bf34 127.0.0.1:6380 master - 0 1496736247773 3 connected 5462-6917 6919-10922 // 过滤掉从节点和未指派槽的主节点
能够看到6380
节点负责的槽变为5462-6917 6919-10922
,而6918
已经被6385
节点负责了。
开始的时候,咱们加入了两个新节点到集群中,节点6385
已经迁移了槽位和数据做为主节点,可是该节点还不具备故障转移的能力。
此时,还须要将6386
节点做为6385
节点的从节点,从而保证集群的高可用。使用cluster replicate <master_id>
命令为主节点添加从节点,集群模式下不支持slaveof
命令。
127.0.0.1:6386> CLUSTER REPLICATE cb987394a3acc7a5e606c72e61174b48e437cedb OK 127.0.0.1:6386> CLUSTER NODES cb987394a3acc7a5e606c72e61174b48e437cedb 127.0.0.1:6385 master - 0 1496742992748 10 connected 6918 cdfb1656353c5c7f29d0330a754c71d53cec464c 127.0.0.1:6386 myself,slave cb987394a3acc7a5e606c72e61174b48e437cedb 0 0 0 connected
到此就完成了集群的扩容。集群关系以下图所示:
收缩集群觉得着缩减规模,须要从集群中安全下线部分节点。须要考虑两种状况:
咱们此次使用redis-trib.rb
工具来下线迁移槽。流程和扩容集群很是类似,正好方向相反,将6380
变为目标节点,6385
成了源节点。将刚才新扩容的集群收缩回去。
./redis-trib.rb reshard 127.0.0.1:6385 >>> Performing Cluster Check (using node 127.0.0.1:6385) ...... [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)? 1 /*迁移一个槽*/ // 目标节点的id What is the receiving node ID? 8f285670923d4f1c599ecc93367c95a30fb8bf34 /*输入目标`6380`节点的id*/ 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. // 输入要迁移槽的源节点 // all 表示全部节点都是源节点 // done 表示输入完成 Source node #1:cb987394a3acc7a5e606c72e61174b48e437cedb Source node #2:done ..... // 是否当即执行从新分片计划 Do you want to proceed with the proposed reshard plan (yes/no)? yes Moving slot 6918 from 127.0.0.1:6385 to 127.0.0.1:6380: ...
查看一下结果:
127.0.0.1:6380> CLUSTER NODES 8f285670923d4f1c599ecc93367c95a30fb8bf34 127.0.0.1:6380 myself,master - 0 0 11 connected 5462-10922 cb987394a3acc7a5e606c72e61174b48e437cedb 127.0.0.1:6385 master - 0 1496744498017 10 connected
6380
节点已经接管了6385
节点的槽。
最后让集群全部的节点忘记下线节点6385
。执行CLUSTER FORGET <down_node_id>
或者使用工具。
./redis-trib.rb del-node 127.0.0.1:6379 cdfb1656353c5c7f29d0330a754c71d53cec464c >>> Removing node cdfb1656353c5c7f29d0330a754c71d53cec464c from cluster 127.0.0.1:6379 >>> Sending CLUSTER FORGET messages to the cluster... >>> SHUTDOWN the node. ./redis-trib.rb del-node 127.0.0.1:6379 cb987394a3acc7a5e606c72e61174b48e437cedb >>> Removing node cb987394a3acc7a5e606c72e61174b48e437cedb from cluster 127.0.0.1:6379 >>> Sending CLUSTER FORGET messages to the cluster... >>> SHUTDOWN the node.
注意,先下线从节点,在下线主节点,以避免没必要要的全量复制操做。对6379
节点作忘记下线节点的操做,那么通过一段时间,集群中的其余节点也都会忘记。
127.0.0.1:6380> CLUSTER NODES 6fb7dfdb6188a9fe53c48ea32d541724f36434e9 127.0.0.1:6383 slave 8f285670923d4f1c599ecc93367c95a30fb8bf34 0 1496744890808 11 connecte 29978c0169ecc0a9054de7f4142155c1ab70258b 127.0.0.1:6379 master - 0 1496744892814 7 connected 0-5461 66478bda726ae6ba4e8fb55034d8e5e5804223ff 127.0.0.1:6381 master - 0 1496744891810 2 connected 10923-16383 e0c7961a1b07ab655bc31d8dfd583da565ec167d 127.0.0.1:6384 slave 66478bda726ae6ba4e8fb55034d8e5e5804223ff 0 1496744888804 2 connected 8f285670923d4f1c599ecc93367c95a30fb8bf34 127.0.0.1:6380 myself,master - 0 0 11 connected 5462-10922 961097d6be64ebd2fd739ff719e97565a8cee7b5 127.0.0.1:6382 slave 29978c0169ecc0a9054de7f4142155c1ab70258b 0 1496744889805 7 connected
6380
端口的主节点已经忘记了下线节点,所以下线节点已经安全的下线。