一 Redis Cluser介绍背景
1.1问题
1
2
3
1 并发量:单机redis qps为10w/s,但是我们可能需要百万级别的并发量
2 数据量:机器内存16g--256g,如果存500g数据呢?
1.2 解决
1
2
redis cluster 在2015 年的 3.0 版本加入了,满足分布式的需求
二 数据分布(分布式数据库)
2.1 存在问题
1
假设全量的数据非常大,500g,单机已经无法满足,我们需要进行分区,分到若干个子集中
2.2 分区方式
分布方式 特点 产品
哈希分布
数据分散度高,建值分布于业务无关,无法顺序访问,支持批量操作
一致性哈希memcache,redis cluster,其他缓存产品
顺序分布
数据分散度易倾斜,建值业务相关,可顺序访问,支持批量操作
BigTable,HBase
2.2.1 顺序分区
2.2.2 哈希分区
2.2.2 .1 节点取余分区
节点扩容,添加一个节点,存在问题,很多数据需要偏移,总偏移量要大于80%
推荐翻倍扩容,由3变成6,数据量迁移为50%,比80%降低
1
2
3
4
客户端分片,通过hash +取余
节点伸缩,数据节点关系发生变化,导致影响数据迁移过大
迁移数量和添加节点数量有关:建议翻倍扩容
2.2.2 .2 一致性哈希分区
每个节点负责一部分数据,对key进行hash,得到结果在node1和node2之间,就放到node2中,顺时针查找
假设添加一个新节点node5,现在只需要迁移一小部分数据,不会影响node3和node4的数据,只会迁移node1和node2的数据
节点比较多的话合适,假设有1000个节点,加一个只要迁移千分之一的数据
1
2
3
4
客户端分片:哈希+顺时针(优化取余)
节点伸缩:只影响临近节点,但是还有数据迁移的情况
伸缩:保证最小迁移数据和无法保证负载均衡(这样总共5 个节点,数据就不均匀了),翻倍扩容可以实现负载均衡
2.2.2 .3 虚拟槽分区
预设虚拟槽:每个槽映射一个数据子集,一般比节点数大
良好的哈希函数:如CRC16
服务端管理节点、槽、数据:如redis cluster(槽的范围0–16383)
1
2
5 个节点,把16384 个槽平均分配到每个节点,客户端会把数据发送给任意一个节点,通过CRC16对key进行哈希对16383 进行取余,算出当前key属于哪部分槽,属于哪个节点,每个节点都会记录是不是负责这部分槽,如果是负责的,进行保存,如果槽不在自己范围内,redis cluster是共享消息的模式,它知道哪个节点负责哪些槽,返回结果,让客户端找对应的节点去存
服务端管理节点,槽,关系
三 集群搭建
3. 1 单机架构
3.2 分布式架构
每个节点之间相互通信,都负责读写,客户端去存,如果不是当前节点,会返回应该存到哪个节点
3.3 Redis Cluster架构
节点,meet,指派槽,复制,高可用
meet解释
A meet一下C,C回复一下,A meet一下B ,B回复一下,这样B和C也能相互感知,A,B,C之间就可以相关交互数据,所有节点共享消息
指派槽
总共有16384个槽,平均分配到每个节点上
3.4 原生安装
1 配置开启节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
port ${port}
daemonize yes
dir "/opt/redis/redis/data/"
logfile "${port}.log"
cluster-enabled yes
cluster-node-timeout 15000
cluster-config-file nodes-${port}.conf
cluster-require-full-coverage yes
redis-server redis-7000. conf
redis-server redis-7001. conf
redis-server redis-7002. conf
redis-server redis-7003. conf
redis-server redis-7004. conf
redis-server redis-7005. conf
2 meet(相互通信)
1
2
3
4
5
redis-cli -h 127.0 .0 .1 -p 7000 cluster meet 127.0 .0 .1 7001
redis-cli -h 127.0 .0 .1 -p 7000 cluster meet 127.0 .0 .1 7002
redis-cli -h 127.0 .0 .1 -p 7000 cluster meet 127.0 .0 .1 7003
redis-cli -h 127.0 .0 .1 -p 7000 cluster meet 127.0 .0 .1 7004
redis-cli -h 127.0 .0 .1 -p 7000 cluster meet 127.0 .0 .1 7005
3 指派槽
1
2
3
redis-cli -h 127.0 .0 .1 -p 7000 cluster addslots {0. ..5461 }
redis-cli -h 127.0 .0 .1 -p 7000 cluster addslots {5462. ..10922 }
redis-cli -h 127.0 .0 .1 -p 7000 cluster addslots {10923. ..16383 }
4 主从
1
2
3
4
5
redis-cli -h 127.0 .0 .1 -p 7003 cluster replicate ${node-id -7000 }
redis-cli -h 127.0 .0 .1 -p 7004 cluster replicate ${node-id -7001 }
redis-cli -h 127.0 .0 .1 -p 7005 cluster replicate ${node-id -7002 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
cd /opt/soft/redis/config
vim redis-7000. conf
port 7000
daemonize yes
dir "/opt/soft/redis/data/"
logfile "7000.log"
dbfilename "dump-7000.rdb"
cluster-enabled yes
cluster-config-file nodes-7000. conf
cluster-require-full-coverage yes
sed 's/7000/7001/g' redis-7000. conf > redis-7001. conf
sed 's/7000/7002/g' redis-7000. conf > redis-7002. conf
sed 's/7000/7003/g' redis-7000. conf > redis-7003. conf
sed 's/7000/7004/g' redis-7000. conf > redis-7004. conf
sed 's/7000/7005/g' redis-7000. conf > redis-7005. conf
./src/redis-server ./config/redis-7000. conf
ps -ef |grep redis
./src/redis-server ./config/redis-7001. conf
./src/redis-server ./config/redis-7002. conf
./src/redis-server ./config/redis-7003. conf
./src/redis-server ./config/redis-7004. conf
./src/redis-server ./config/redis-7005. conf
redis-cli -p 7000
set hello world
redis-cli -p 7000 cluster nodes
redis-cli -p 7000 cluster info
redis-cli -p 7000 cluster meet 127.0 .0 .1 7001
redis-cli -p 7000 cluster nodes
redis-cli -p 7002 cluster nodes
redis-cli -p 7000 cluster meet 127.0 .0 .1 7002
redis-cli -p 7000 cluster meet 127.0 .0 .1 7003
redis-cli -p 7000 cluster meet 127.0 .0 .1 7004
redis-cli -p 7000 cluster meet 127.0 .0 .1 7005
redis-cli -p 7000 cluster info
redis-cli -p 7000 cluster addslots 0
mkdir script
cd script
vim addslots.sh
start=$1
end=$2
port=$3
for slot in `seq ${start} ${end}`
do
echo "slot:${slot}"
done
sh addslots.sh 0 4096 7000
start=$1
end=$2
port=$3
for slot in `seq ${start} ${end}`
do
echo "slot:${slot}"
redis-cli -p ${port} cluster addslots ${slot}
done
sh addslots.sh 0 5641 7000
redis-cli -p 7000
cluster info
cluster nodes
sh addslots.sh 5641 10922 7001
sh addslots.sh 10923 16383 7002
redis-cli -p 7000 cluster info
redis-cli -p 7003 cluster replicate 7000id
redis-cli -p 7004 cluster replicate 7001id
redis-cli -p 7005 cluster replicate 7002id
redis-cli -p 7000 cluster info
redis-cli -p 7000 cluster nodes
redis-cli -p 7000 cluster slots
redis-cli -c -p 7000
set hello world
3.5 官方工具安装(Ruby脚本)
准备环境
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
wget https://cache.ruby-lang.org/pub/ruby/2.5 /ruby-2.5 .8 .tar.gz
tar -zxvf ruby-2.5 .8 .tar.gz
cd ruby
./configure -prefix=/usr/local/ruby
make && make install
cd /usr/local/ruby
cp bin /ruby /usr/local/bin
cp bin /gem /usr/local/bin
ruby -v
gem sources -l
gem sources --remove https://rubygems.org/
gem sources -a https://gems.ruby-china.com/
gem sources -l
gem install redis -v 3.3 .3
gem list check redis gem
cd /opt/soft/redis/src
./redis-trib.rb 弃用了,需要使用
redis-cli --cluster create --cluster-replicas 1 127.0 .0 .1 :7000 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
yes
四 集群伸缩
伸缩原理
集群扩容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
-集群模式
-配置和其他节点统一
-启动后是孤儿节点
sed 's/7000/7006/g' redis-7000. conf > redis-7006. conf
sed 's/7000/7007/g' redis-7000. conf > redis-7007. conf
redis-server conf/redis-7006. conf
redis-server conf/redis-7007. conf
redis-cli -p 7006 cluster nodes
在7000 上执行
redis-cli -p 7000 cluster meet 127.0 .0 .1 7006
redis-cli -p 7000 cluster meet 127.0 .0 .1 7007
redis-cli --cluster add-node 127.0 .0 .1 :7006 127.0 .0 .1 :7000
redis-cli --cluster add-node 127.0 .0 .1 :7007 127.0 .0 .1 :7000
cluster nodes
redis-cli -p 7007 cluster replicate 7006 的id
redis-cli --cluster reshard 127.0 .0 .1 :7000
redis-cli -p 7000 cluster nodes
redis-cli -p 7000 cluster slots
1
2
3
4
5
-如果想给7000 再加一个从节点怎么弄?
redis-cli -p 7000 cluster meet 127.0 .0 .1 7006
redis-cli -p 7006 cluster replicate e03fb9a259cd314e9a23e17573d07c477d3242f7
集群缩容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
redis-cli --cluster reshard --cluster-from 7006 的id --cluster-to 7000 的id --cluster-slots 1366 127.0 .0 .1 :7000
yes
redis-cli --cluster reshard --cluster-from 7006 的id --cluster-to 7001 的id --cluster-slots 1366 127.0 .0 .1 :7001
yes
redis-cli --cluster reshard --cluster-from 7006 的id --cluster-to 7002 的id --cluster-slots 1365 127.0 .0 .1 :7002
yes
redis-cli --cluster del -node 127.0 .0 .1 :7000 要下线的7007id
redis-cli --cluster del -node 127.0 .0 .1 :7000 要下线的7006id
五 客户端连接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
redis-cli -c -p 7000
set hello world
cluster keyslot php
set php sb
from rediscluster import RedisCluster
startup_nodes = [{"host" :"127.0.0.1" , "port" : "7000" },{"host" :"127.0.0.1" , "port" : "7001" },{"host" :"127.0.0.1" , "port" : "7002" }]
rc = RedisCluster(startup_nodes=startup_nodes)
rc.set ("foo" , "bar" )
print (rc.get("foo" ))
六 集群原理
move重定向
槽命中
cluster keyslot hello 可以计算出槽的值
槽不命中:moved异常
七 补充
7.1 5.0以后集群搭建
Redis Cluster 在5.0之后取消了ruby脚本 redis-trib.rb 的支持(手动命令行添加集群的方式不变),集合到redis-cli里,避免了再安装ruby的相关环境。直接使用redis-clit的参数–cluster 来取代
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
redis-cli --cluster help
Cluster Manager Commands:
create host1:port1 ... hostN:portN
--cluster-replicas <arg>
check host:port
--cluster-search-multiple-owners
info host:port
fix host:port
--cluster-search-multiple-owners
reshard host:port
--cluster-from <arg>
--cluster-to <arg>
--cluster-slots <arg>
--cluster-yes
--cluster-timeout <arg>
--cluster-pipeline <arg>
--cluster-replace
rebalance host:port
--cluster-weight <node1=w1...nodeN=wN>
--cluster-use-empty-masters
--cluster-timeout <arg>
--cluster-simulate
--cluster-pipeline <arg>
--cluster-threshold <arg>
--cluster-replace
add-node new_host:new_port existing_host:existing_port
--cluster-slave
--cluster-master-id <arg>
del -node host:port node_id
call host:port command arg arg .. arg
set -timeout host:port milliseconds
import host:port
--cluster-from <arg>
--cluster-copy
--cluster-replace
help
For check, fix, reshard, del -node, set -timeout you can specify the host and port of any working node in the cluster.
① 创建集群主节点
1
redis-cli --cluster create 192.168 .163.132 :6379 192.168 .163.132 :6380 192.168 .163.132 :6381
② 创建集群主从节点
说明:–cluster-replicas 参数为数字,1表示每个主节点需要1个从节点。
通过该方式创建的带有从节点的机器不能够自己手动指定主节点,所以如果需要指定的话,需要自己手动指定,先使用①或③创建好主节点后,再通过④来处理。
③ 添加集群主节点
1
redis-cli --cluster add-node 192.168 .163.132 :6382 192.168 .163.132 :6379
说明:为一个指定集群添加节点,需要先连到该集群的任意一个节点IP(192.168.163.132:6379),再把新节点加入。该2个参数的顺序有要求:新加入的节点放前
④ 添加集群从节点
1
redis-cli --cluster add-node 192.168 .163.132 :6382 192.168 .163.132 :6379 --cluster-slave --cluster-master-id 117457 eab5071954faab5e81c3170600d5192270
说明:把6382节点加入到6379节点的集群中,并且当做node_id为 117457eab5071954faab5e81c3170600d5192270 的从节点。如果不指定 –cluster-master-id 会随机分配到任意一个主节点。
⑤ 删除节点
1
redis-cli --cluster del -node 192.168 .163.132 :6384 f6a6957421b80409106cb36be3c7ba41f3b603ff
说明:指定IP、端口和node_id 来删除一个节点,从节点可以直接删除,主节点不能直接删除,删除之后,该节点会被shutdown。
注意:当被删除掉的节点重新起来之后不能自动加入集群,但其和主的复制还是正常的,也可以通过该节点看到集群信息(通过其他正常节点已经看不到该被del-node节点的信息)。
如果想要再次加入集群,则需要先在该节点执行cluster reset,再用add-node进行添加,进行增量同步复制。
到此,目前整个集群的状态如下:
1
2
3
4
5
6
7
192.168 .163.132 :6379 > cluster nodes
815 da8448f5d5a304df0353ca10d8f9b77016b28 192.168 .163.132 :6380 @16380 master - 0 1569748297177 2 connected 5461 -10922
0 c21b6cee354594a23f4d5abf0d01b48bdc96d55 192.168 .163.132 :6383 @16383 slave 56005 b9413cbf225783906307a2631109e753f8f 0 1569748295000 4 connected
3 a1d04983ab6c4ae853f9602dd922d4ebadc4dbf 192.168 .163.132 :6382 @16382 slave 815 da8448f5d5a304df0353ca10d8f9b77016b28 0 1569748295000 5 connected
117457 eab5071954faab5e81c3170600d5192270 192.168 .163.132 :6379 @16379 myself,master - 0 1569748297000 1 connected 0 -5460
56005 b9413cbf225783906307a2631109e753f8f 192.168 .163.132 :6381 @16381 master - 0 1569748295000 3 connected 10923 -16383
f6a6957421b80409106cb36be3c7ba41f3b603ff 192.168 .163.132 :6384 @16384 slave 117457 eab5071954faab5e81c3170600d5192270 0 1569748298185 6 connected
⑥ 检查集群
1
redis-cli --cluster check 192.168 .163.132 :6384 --cluster-search-multiple-owners
说明:任意连接一个集群节点,进行集群状态检查
⑦ 集群信息查看
1
redis-cli --cluster info 192.168 .163.132 :6384
说明:检查key、slots、从节点个数的分配情况
1
2
3
4
5
6
/redis-cli --cluster info 192.168 .163.132 :6384
192.168 .163.132 :6380 (815 da844...) -> 0 keys | 5462 slots | 1 slaves.
192.168 .163.132 :6381 (56005 b94...) -> 0 keys | 5461 slots | 1 slaves.
192.168 .163.132 :6379 (117457 ea...) -> 2 keys | 5461 slots | 1 slaves.
[OK] 2 keys in 3 masters.
0 .00 keys per slot on average.
⑧ 修复集群
1
redis-cli --cluster fix 192.168 .163.132 :6384 --cluster-search-multiple-owners
说明:修复集群和槽的重复分配问题
⑨ 设置集群的超时时间
1
redis-cli --cluster set-timeout 192.168 .163.132 :6382 10000
说明:连接到集群的任意一节点来设置集群的超时时间参数cluster-node-timeout
1
2
3
4
5
6
7
8
9
redis-cli --cluster set-timeout 192.168 .163.132 :6382 10000
>>> Reconfiguring node timeout in every cluster node...
*** New timeout set for 192.168 .163.132 :6382
*** New timeout set for 192.168 .163.132 :6384
*** New timeout set for 192.168 .163.132 :6383
*** New timeout set for 192.168 .163.132 :6379
*** New timeout set for 192.168 .163.132 :6381
*** New timeout set for 192.168 .163.132 :6380
>>> New node timeout set. 6 OK, 0 ERR.
⑩ 集群中执行相关命令
1
2
3
redis-cli --cluster call 192.168 .163.132 :6381 config set requirepass cc
redis-cli -a cc --cluster call 192.168 .163.132 :6381 config set masterauth cc
redis-cli -a cc --cluster call 192.168 .163.132 :6381 config rewrite
说明:连接到集群的任意一节点来对整个集群的所有节点进行设置。
1
2
3
4
5
6
7
8
9
10
redis-cli --cluster call 192.168 .163.132 :6381 config set cluster-node-timeout 12000
>>> Calling config set cluster-node-timeout 12000
192.168 .163.132 :6381 : OK
192.168 .163.132 :6383 : OK
192.168 .163.132 :6379 : OK
192.168 .163.132 :6384 : OK
192.168 .163.132 :6382 : OK
192.168 .163.132 :6380 : OK
...
...
到此,相关集群的基本操作已经介绍完,现在说明集群迁移的相关操作。
迁移相关
① 在线迁移slot :在线把集群的一些slot从集群原来slot节点迁移到新的节点,即可以完成集群的在线横向扩容和缩容。有2种方式进行迁移
一是根据提示来进行操作:
1
2
直接连接到集群的任意一节点
redis-cli -a cc --cluster reshard 192.168 .163.132 :6379
信息如下:
二是根据参数进行操作:
1
redis-cli -a cc --cluster reshard 192.168 .163.132 :6379 --cluster-from 117457 eab5071954faab5e81c3170600d5192270 --cluster-to 815 da8448f5d5a304df0353ca10d8f9b77016b28 --cluster-slots 10 --cluster-yes --cluster-timeout 5000 --cluster-pipeline 10 --cluster-replace
说明:连接到集群的任意一节点来对指定节点指定数量的slot进行迁移到指定的节点。
② 平衡(rebalance)slot :
1)平衡集群中各个节点的slot数量
1
redis-cli -a cc --cluster rebalance 192.168 .163.132 :6379
2)根据集群中各个节点设置的权重等平衡slot数量(不执行,只模拟)
③ 导入集群
1
redis-cli --cluster import 192.168 .163.132 :6379 --cluster-from 192.168 .163.132 :9021 --cluster-replace
说明:外部Redis实例(9021)导入到集群中的任意一节点。
注意:测试下来发现参数–cluster-replace没有用,如果集群中已经包含了某个key,在导入的时候会失败,不会覆盖,只有清空集群key才能导入。
1
2
3
*** Importing 97847 keys from DB 0
Migrating 9223372011174675807 to 192.168 .163.132 :6381 : Source 192.168 .163.132 :9021 replied with error:
ERR Target instance replied with error: BUSYKEY Target key name already exists
并且发现如果集群设置了密码,也会导入失败,需要设置集群密码为空才能进行导入(call)。通过monitor(9021)的时候发现,在migrate的时候需要密码进行auth认证。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix