2019独角兽企业重金招聘Python工程师标准>>>

Redis Cluster 集群伸缩

1. 伸缩原理

Redis提供了灵活的节点扩容和收缩方案。在不影响集群对外服务的情况下,可以为集群添加节点进行扩容也可以对下线节点进行缩容。

我们在Redis Cluster 介绍与搭建这篇文章中搭建了一个三主三从的redis集群(如下图所示)。在搭建 Redis Cluster 通信流程剖析这篇博客中根据源码详细剖析了搭建集群的流程。

本篇博客要讲的是,Redis集群的扩容和缩容过程。

我们先根据Redis Cluster 介绍与搭建将如图的集群搭建起来,查看搭建的效果。

127.0.0.1:6379> cluster nodes
29978c0169ecc0a9054de7f4142155c1ab70258b 127.0.0.1:6379 myself,master - 0 0 7 connected 0-54618f285670923d4f1c599ecc93367c95a30fb8bf34 127.0.0.1:6380 master - 0 1496717082785 3 connected 5462-1092266478bda726ae6ba4e8fb55034d8e5e5804223ff 127.0.0.1:6381 master - 0 1496717085793 2 connected 10923-16383961097d6be64ebd2fd739ff719e97565a8cee7b5 127.0.0.1:6382 slave 29978c0169ecc0a9054de7f4142155c1ab70258b 0 1496717084791 7 connected6fb7dfdb6188a9fe53c48ea32d541724f36434e9 127.0.0.1:6383 slave 8f285670923d4f1c599ecc93367c95a30fb8bf34 0 1496717087797 4 connectede0c7961a1b07ab655bc31d8dfd583da565ec167d 127.0.0.1:6384 slave 66478bda726ae6ba4e8fb55034d8e5e5804223ff 0 1496717086795 2 connected

对应的主节点负责的槽位信息,如下图所示:

2. 扩容集群

扩容集群是分布式存储最常见的需求,Redis集群扩容可以分为如下步骤:

准备新节点

加入集群

迁移槽和数据

2.1 准备新节点

我们需要两个节点,端口分别为6385和6386,配置和之前集群节点配置基本相同,除了端口不同,以便于管理。6385节点配置如下:

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

启动后的新节点会作为孤儿节点运行,没有和其他节点与之通信。

2.2 加入集群

我们可以通过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
......

这两种方法可以,新加入的节点都是主节点,因为没有负责槽位,所以不能接受任何读写操作,对于新加入的节点,我们可以有两个操作:

为新节点迁移槽和数据实现扩容。

作为其他主节点的从节点负责故障转移。

2.3 迁移槽和数据

当我们将新节点加入集群后,我们就可以将槽和数据迁移到新的节点,迁移的方法也有两种,可以使用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

到此就完成了集群的扩容。集群关系如下图所示:

3. 收缩集群

收缩集群以为着缩减规模,需要从集群中安全下线部分节点。需要考虑两种情况:

确定下线的节点是否有负责槽,如果是,需要把槽迁移到其他节点,保证节点下线后整个槽节点映射的完整性。

当下线节点不在负责槽或着本身是从节点时,就可以通知集群内其他节点忘记下线节点,当所有节点忘记该节点后就可以正常关闭。

我们这次使用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端口的主节点已经忘记了下线节点,因此下线节点已经安全的下线。

转载于:https://my.oschina.net/gaoenwei/blog/1624426

Redis Cluster 集群扩容与收缩相关推荐

  1. Redis cluster集群扩容缩容原理

    1. Redis Cluster集群扩容 1.1 扩容原理 redis cluster可以实现对节点的灵活上下线控制 3个主节点分别维护自己负责的槽和对应的数据,如果希望加入一个节点实现扩容,就需要把 ...

  2. Redis Cluster 集群模式原理和动态扩容

    Redis Cluster原理 详细参考 Redis cluster集群模式的原理, 在这里补充下要点 16384个slot, 平均分布在各个master, key-value 对存储在slot中; ...

  3. redis集群扩容和缩容_深入理解Redis Cluster集群

    一.背景 前面的文章<深入理解Redis哨兵机制>一文中介绍了Redis哨兵集群的工作原理,哨兵集群虽然满足了高可用的特性,但是依然存在这样的问题:即数据只能往一个主节点上进行写入. 只能 ...

  4. redis cluster 集群 HA 原理和实操(史上最全、面试必备)

    文章很长,建议收藏起来慢慢读!疯狂创客圈总目录 语雀版 | 总目录 码云版| 总目录 博客园版 为您奉上珍贵的学习资源 : 免费赠送 经典图书:<Java高并发核心编程(卷1)> 面试必备 ...

  5. Redis Cluster集群知识学习总结

    Redis集群解决方案有两个: 1)  Twemproxy: 这是Twitter推出的解决方案,简单的说就是上层加个代理负责分发,属于client端集群方案,目前很多应用者都在采用的解决方案.Twem ...

  6. Redis学习(二)之 Redis Cluster集群

    redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态,如果master节点异常,则会做主从切换,将某一台slave作为master,哨兵的配置略微复杂,并 ...

  7. Redis Cluster集群建设

    内容覆盖 1.Redis 单点部署. 2.Redis Cluster集群建设. 3.Redis Cluster集群节点扩容. 4.Redis 密码修改. Redis Cluster简介 Redis C ...

  8. Redis——cluster集群原理

    摘要 在 redis3.0之前,redis使用的哨兵架构,它借助 sentinel 工具来监控 master 节点的状态:如果 master 节点异常,则会做主从切换,将一台 slave 作为 mas ...

  9. Redis Cluster 集群详解

    Redis 分布式扩展之 Redis Cluster 方案 主从切换的过程中会丢失数据,因为只有一个 master,只能单点写,没有解决水平扩容的问题.而且每个节点都保存了所有数据,一个是内存的占用率 ...

最新文章

  1. 单选框-复选框重置的方法
  2. 【S操作】轻松优雅防止(解决)两次掉进同一坑的完美解决方案
  3. hdu 5358(尺取法)
  4. boost::core::is_same用法测试实例
  5. 『 天池竞赛』O2O优惠券使用预测思路总结
  6. python之按位运算
  7. [转]Eclipse Java注释模板设置详解
  8. fetch ajax cros,由 Fetch 跨域 看 CORS
  9. Spring Cloud 服务消费者 rest+ribbon (二)
  10. 【WiFi】WiFi 5G 信道、频宽对应关系及支持的信道列表
  11. oracle 大于当天时间_ORACLE日期时间函数大全
  12. czl蒻蒟的OI之路
  13. 我的 Typora IDEA 雅黑主题
  14. nfc java_NFC 开发
  15. android 百度转码,自适应网站移动端被百度转码解决方案
  16. 我写了个随机点名系统,非常好用~ 我给它取名叫做——随机点名系统
  17. 亚马逊云科技携手埃森哲共助行业云转型
  18. 用wrap加密自己的源代码
  19. 总结 | 有关激光雷达的QA
  20. matlab 变成圆形坐标,求圆和椭圆上任意角度的点的坐标

热门文章

  1. iOS UIWebView 之 UIProgressView
  2. phpcms图片无法上传
  3. elasticsearch映射相关字段定义,属性定义,及动态映射(marvel插件方式)mapping
  4. IDEA的postfix自定义,自定义postfix
  5. 接口测试工具--Apipost不同脚本的作用
  6. ijkplayer 视频播放
  7. 02-01 Python 安装与pip
  8. 自学前端,需要学习哪些知识点?学多久可以入职前端工程师?
  9. LeetCode 496. 下一个更大元素 I
  10. 函数栈帧的创建和销毁图解